sempass2.nim 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587
  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, lineinfos, semfold, semdata,
  12. modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling, tables,
  13. semstrictfuncs
  14. when defined(nimPreviewSlimSystem):
  15. import std/assertions
  16. when defined(useDfa):
  17. import dfa
  18. import liftdestructors
  19. include sinkparameter_inference
  20. #[ Second semantic checking pass over the AST. Necessary because the old
  21. way had some inherent problems. Performs:
  22. * effect+exception tracking
  23. * "usage before definition" checking
  24. * also now calls the "lift destructor logic" at strategic positions, this
  25. is about to be put into the spec:
  26. We treat assignment and sinks and destruction as identical.
  27. In the construct let/var x = expr() x's type is marked.
  28. In x = y the type of x is marked.
  29. For every sink parameter of type T T is marked.
  30. For every call f() the return type of f() is marked.
  31. ]#
  32. # ------------------------ exception and tag tracking -------------------------
  33. discard """
  34. exception tracking:
  35. a() # raises 'x', 'e'
  36. try:
  37. b() # raises 'e'
  38. except e:
  39. # must not undo 'e' here; hrm
  40. c()
  41. --> we need a stack of scopes for this analysis
  42. # XXX enhance the algorithm to care about 'dirty' expressions:
  43. lock a[i].L:
  44. inc i # mark 'i' dirty
  45. lock a[j].L:
  46. access a[i], a[j] # --> reject a[i]
  47. """
  48. type
  49. TEffects = object
  50. exc: PNode # stack of exceptions
  51. tags: PNode # list of tags
  52. forbids: PNode # list of tags
  53. bottom, inTryStmt, inExceptOrFinallyStmt, leftPartOfAsgn, inIfStmt, currentBlock: int
  54. owner: PSym
  55. ownerModule: PSym
  56. init: seq[int] # list of initialized variables
  57. scopes: Table[int, int] # maps var-id to its scope (see also `currentBlock`).
  58. guards: TModel # nested guards
  59. locked: seq[PNode] # locked locations
  60. gcUnsafe, isRecursive, isTopLevel, hasSideEffect, inEnforcedGcSafe: bool
  61. isInnerProc: bool
  62. inEnforcedNoSideEffects: bool
  63. currOptions: TOptions
  64. config: ConfigRef
  65. graph: ModuleGraph
  66. c: PContext
  67. escapingParams: IntSet
  68. PEffects = var TEffects
  69. const
  70. errXCannotBeAssignedTo = "'$1' cannot be assigned to"
  71. errLetNeedsInit = "'let' symbol requires an initialization"
  72. proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) =
  73. if typ == nil or sfGeneratedOp in tracked.owner.flags:
  74. # don't create type bound ops for anything in a function with a `nodestroy` pragma
  75. # bug #21987
  76. return
  77. when false:
  78. let realType = typ.skipTypes(abstractInst)
  79. if realType.kind == tyRef and
  80. optSeqDestructors in tracked.config.globalOptions:
  81. createTypeBoundOps(tracked.graph, tracked.c, realType.lastSon, info)
  82. createTypeBoundOps(tracked.graph, tracked.c, typ, info, tracked.c.idgen)
  83. if (tfHasAsgn in typ.flags) or
  84. optSeqDestructors in tracked.config.globalOptions:
  85. tracked.owner.flags.incl sfInjectDestructors
  86. proc isLocalSym(a: PEffects, s: PSym): bool =
  87. s.typ != nil and (s.kind in {skLet, skVar, skResult} or (s.kind == skParam and isOutParam(s.typ))) and
  88. sfGlobal notin s.flags and s.owner == a.owner
  89. proc lockLocations(a: PEffects; pragma: PNode) =
  90. if pragma.kind != nkExprColonExpr:
  91. localError(a.config, pragma.info, "locks pragma without argument")
  92. return
  93. for x in pragma[1]:
  94. a.locked.add x
  95. proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
  96. # check whether the corresponding lock is held:
  97. for L in a.locked:
  98. if L.kind == nkSym and L.sym == guard: return
  99. # we allow accesses nevertheless in top level statements for
  100. # easier initialization:
  101. #if a.isTopLevel:
  102. # message(a.config, n.info, warnUnguardedAccess, renderTree(n))
  103. #else:
  104. if not a.isTopLevel:
  105. localError(a.config, n.info, "unguarded access: " & renderTree(n))
  106. # 'guard*' are checks which are concerned with 'guard' annotations
  107. # (var x{.guard: y.}: int)
  108. proc guardDotAccess(a: PEffects; n: PNode) =
  109. let ri = n[1]
  110. if ri.kind != nkSym or ri.sym.kind != skField: return
  111. var g = ri.sym.guard
  112. if g.isNil or a.isTopLevel: return
  113. # fixup guard:
  114. if g.kind == skUnknown:
  115. var field: PSym = nil
  116. var ty = n[0].typ.skipTypes(abstractPtrs)
  117. if ty.kind == tyTuple and not ty.n.isNil:
  118. field = lookupInRecord(ty.n, g.name)
  119. else:
  120. while ty != nil and ty.kind == tyObject:
  121. field = lookupInRecord(ty.n, g.name)
  122. if field != nil: break
  123. ty = ty[0]
  124. if ty == nil: break
  125. ty = ty.skipTypes(skipPtrs)
  126. if field == nil:
  127. localError(a.config, n.info, "invalid guard field: " & g.name.s)
  128. return
  129. g = field
  130. #ri.sym.guard = field
  131. # XXX unfortunately this is not correct for generic instantiations!
  132. if g.kind == skField:
  133. let dot = newNodeI(nkDotExpr, n.info, 2)
  134. dot[0] = n[0]
  135. dot[1] = newSymNode(g)
  136. dot.typ = g.typ
  137. for L in a.locked:
  138. #if a.guards.sameSubexprs(dot, L): return
  139. if guards.sameTree(dot, L): return
  140. localError(a.config, n.info, "unguarded access: " & renderTree(n))
  141. else:
  142. guardGlobal(a, n, g)
  143. proc makeVolatile(a: PEffects; s: PSym) {.inline.} =
  144. if a.inTryStmt > 0 and a.config.exc == excSetjmp:
  145. incl(s.flags, sfVolatile)
  146. proc varDecl(a: PEffects; n: PNode) {.inline.} =
  147. if n.kind == nkSym:
  148. a.scopes[n.sym.id] = a.currentBlock
  149. proc skipHiddenDeref(n: PNode): PNode {.inline.} =
  150. result = if n.kind == nkHiddenDeref: n[0] else: n
  151. proc initVar(a: PEffects, n: PNode; volatileCheck: bool) =
  152. let n = skipHiddenDeref(n)
  153. if n.kind != nkSym: return
  154. let s = n.sym
  155. if isLocalSym(a, s):
  156. if volatileCheck: makeVolatile(a, s)
  157. for x in a.init:
  158. if x == s.id:
  159. if strictDefs in a.c.features and s.kind == skLet:
  160. localError(a.config, n.info, errXCannotBeAssignedTo %
  161. renderTree(n, {renderNoComments}
  162. ))
  163. return
  164. a.init.add s.id
  165. if a.scopes.getOrDefault(s.id) == a.currentBlock:
  166. #[ Consider this case:
  167. var x: T
  168. while true:
  169. if cond:
  170. x = T() #1
  171. else:
  172. x = T() #2
  173. use x
  174. Even though both #1 and #2 are first writes we must use the `=copy`
  175. here so that the old value is destroyed because `x`'s destructor is
  176. run outside of the while loop. This is why we need the check here that
  177. the assignment is done in the same logical block as `x` was declared in.
  178. ]#
  179. n.flags.incl nfFirstWrite
  180. proc initVarViaNew(a: PEffects, n: PNode) =
  181. let n = skipHiddenDeref(n)
  182. if n.kind != nkSym: return
  183. let s = n.sym
  184. if {tfRequiresInit, tfNotNil} * s.typ.flags <= {tfNotNil}:
  185. # 'x' is not nil, but that doesn't mean its "not nil" children
  186. # are initialized:
  187. initVar(a, n, volatileCheck=true)
  188. elif isLocalSym(a, s):
  189. makeVolatile(a, s)
  190. proc warnAboutGcUnsafe(n: PNode; conf: ConfigRef) =
  191. #assert false
  192. message(conf, n.info, warnGcUnsafe, renderTree(n))
  193. proc markGcUnsafe(a: PEffects; reason: PSym) =
  194. if not a.inEnforcedGcSafe:
  195. a.gcUnsafe = true
  196. if a.owner.kind in routineKinds: a.owner.gcUnsafetyReason = reason
  197. proc markGcUnsafe(a: PEffects; reason: PNode) =
  198. if not a.inEnforcedGcSafe:
  199. a.gcUnsafe = true
  200. if a.owner.kind in routineKinds:
  201. if reason.kind == nkSym:
  202. a.owner.gcUnsafetyReason = reason.sym
  203. else:
  204. a.owner.gcUnsafetyReason = newSym(skUnknown, a.owner.name, a.c.idgen,
  205. a.owner, reason.info, {})
  206. proc markSideEffect(a: PEffects; reason: PNode | PSym; useLoc: TLineInfo) =
  207. if not a.inEnforcedNoSideEffects:
  208. a.hasSideEffect = true
  209. if a.owner.kind in routineKinds:
  210. var sym: PSym
  211. when reason is PNode:
  212. if reason.kind == nkSym:
  213. sym = reason.sym
  214. else:
  215. let kind = if reason.kind == nkHiddenDeref: skParam else: skUnknown
  216. sym = newSym(kind, a.owner.name, a.c.idgen, a.owner, reason.info, {})
  217. else:
  218. sym = reason
  219. a.c.sideEffects.mgetOrPut(a.owner.id, @[]).add (useLoc, sym)
  220. when false: markGcUnsafe(a, reason)
  221. proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet; conf: ConfigRef) =
  222. let u = s.gcUnsafetyReason
  223. if u != nil and not cycleCheck.containsOrIncl(u.id):
  224. let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated
  225. case u.kind
  226. of skLet, skVar:
  227. if u.typ.skipTypes(abstractInst).kind == tyProc:
  228. message(conf, s.info, msgKind,
  229. "'$#' is not GC-safe as it calls '$#'" %
  230. [s.name.s, u.name.s])
  231. else:
  232. message(conf, s.info, msgKind,
  233. ("'$#' is not GC-safe as it accesses '$#'" &
  234. " which is a global using GC'ed memory") % [s.name.s, u.name.s])
  235. of routineKinds:
  236. # recursive call *always* produces only a warning so the full error
  237. # message is printed:
  238. if u.kind == skMethod and {sfBase, sfThread} * u.flags == {sfBase}:
  239. message(conf, u.info, msgKind,
  240. "Base method '$#' requires explicit '{.gcsafe.}' to be GC-safe" %
  241. [u.name.s])
  242. else:
  243. listGcUnsafety(u, true, cycleCheck, conf)
  244. message(conf, s.info, msgKind,
  245. "'$#' is not GC-safe as it calls '$#'" %
  246. [s.name.s, u.name.s])
  247. of skParam, skForVar:
  248. message(conf, s.info, msgKind,
  249. "'$#' is not GC-safe as it performs an indirect call via '$#'" %
  250. [s.name.s, u.name.s])
  251. else:
  252. message(conf, u.info, msgKind,
  253. "'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
  254. proc listGcUnsafety(s: PSym; onlyWarning: bool; conf: ConfigRef) =
  255. var cycleCheck = initIntSet()
  256. listGcUnsafety(s, onlyWarning, cycleCheck, conf)
  257. proc listSideEffects(result: var string; s: PSym; cycleCheck: var IntSet;
  258. conf: ConfigRef; context: PContext; indentLevel: int) =
  259. template addHint(msg; lineInfo; sym; level = indentLevel) =
  260. result.addf("$# $# Hint: '$#' $#\n", repeat(">", level), conf $ lineInfo, sym, msg)
  261. if context.sideEffects.hasKey(s.id):
  262. for (useLineInfo, u) in context.sideEffects[s.id]:
  263. if u != nil and not cycleCheck.containsOrIncl(u.id):
  264. case u.kind
  265. of skLet, skVar:
  266. addHint("accesses global state '$#'" % u.name.s, useLineInfo, s.name.s)
  267. addHint("accessed by '$#'" % s.name.s, u.info, u.name.s, indentLevel + 1)
  268. of routineKinds:
  269. addHint("calls `.sideEffect` '$#'" % u.name.s, useLineInfo, s.name.s)
  270. addHint("called by '$#'" % s.name.s, u.info, u.name.s, indentLevel + 1)
  271. listSideEffects(result, u, cycleCheck, conf, context, indentLevel + 2)
  272. of skParam, skForVar:
  273. addHint("calls routine via hidden pointer indirection", useLineInfo, s.name.s)
  274. else:
  275. addHint("calls routine via pointer indirection", useLineInfo, s.name.s)
  276. proc listSideEffects(result: var string; s: PSym; conf: ConfigRef; context: PContext) =
  277. var cycleCheck = initIntSet()
  278. result.addf("'$#' can have side effects\n", s.name.s)
  279. listSideEffects(result, s, cycleCheck, conf, context, 1)
  280. proc useVarNoInitCheck(a: PEffects; n: PNode; s: PSym) =
  281. if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and
  282. s.magic != mNimvm:
  283. if s.guard != nil: guardGlobal(a, n, s.guard)
  284. if {sfGlobal, sfThread} * s.flags == {sfGlobal} and
  285. (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem):
  286. #if a.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n)
  287. markGcUnsafe(a, s)
  288. markSideEffect(a, s, n.info)
  289. if s.owner != a.owner and s.kind in {skVar, skLet, skForVar, skResult, skParam} and
  290. {sfGlobal, sfThread} * s.flags == {}:
  291. a.isInnerProc = true
  292. proc useVar(a: PEffects, n: PNode) =
  293. let s = n.sym
  294. if a.inExceptOrFinallyStmt > 0:
  295. incl s.flags, sfUsedInFinallyOrExcept
  296. if isLocalSym(a, s):
  297. if sfNoInit in s.flags:
  298. # If the variable is explicitly marked as .noinit. do not emit any error
  299. a.init.add s.id
  300. elif s.id notin a.init:
  301. if s.typ.requiresInit:
  302. message(a.config, n.info, warnProveInit, s.name.s)
  303. elif a.leftPartOfAsgn <= 0:
  304. if strictDefs in a.c.features:
  305. if s.kind == skLet:
  306. localError(a.config, n.info, errLetNeedsInit)
  307. else:
  308. message(a.config, n.info, warnUninit, s.name.s)
  309. # prevent superfluous warnings about the same variable:
  310. a.init.add s.id
  311. useVarNoInitCheck(a, n, s)
  312. type
  313. TIntersection = seq[tuple[id, count: int]] # a simple count table
  314. proc addToIntersection(inter: var TIntersection, s: int) =
  315. for j in 0..<inter.len:
  316. if s == inter[j].id:
  317. inc inter[j].count
  318. return
  319. inter.add((id: s, count: 1))
  320. proc throws(tracked, n, orig: PNode) =
  321. if n.typ == nil or n.typ.kind != tyError:
  322. if orig != nil:
  323. let x = copyTree(orig)
  324. x.typ = n.typ
  325. tracked.add x
  326. else:
  327. tracked.add n
  328. proc getEbase(g: ModuleGraph; info: TLineInfo): PType =
  329. result = g.sysTypeFromName(info, "Exception")
  330. proc excType(g: ModuleGraph; n: PNode): PType =
  331. # reraise is like raising E_Base:
  332. let t = if n.kind == nkEmpty or n.typ.isNil: getEbase(g, n.info) else: n.typ
  333. result = skipTypes(t, skipPtrs)
  334. proc createRaise(g: ModuleGraph; n: PNode): PNode =
  335. result = newNode(nkType)
  336. result.typ = getEbase(g, n.info)
  337. if not n.isNil: result.info = n.info
  338. proc createTag(g: ModuleGraph; n: PNode): PNode =
  339. result = newNode(nkType)
  340. result.typ = g.sysTypeFromName(n.info, "RootEffect")
  341. if not n.isNil: result.info = n.info
  342. proc addRaiseEffect(a: PEffects, e, comesFrom: PNode) =
  343. #assert e.kind != nkRaiseStmt
  344. var aa = a.exc
  345. for i in a.bottom..<aa.len:
  346. # we only track the first node that can have the effect E in order
  347. # to safe space and time.
  348. if sameType(a.graph.excType(aa[i]), a.graph.excType(e)): return
  349. if e.typ != nil:
  350. if not isDefectException(e.typ):
  351. throws(a.exc, e, comesFrom)
  352. proc addTag(a: PEffects, e, comesFrom: PNode) =
  353. var aa = a.tags
  354. for i in 0..<aa.len:
  355. # we only track the first node that can have the effect E in order
  356. # to safe space and time.
  357. if sameType(aa[i].typ.skipTypes(skipPtrs), e.typ.skipTypes(skipPtrs)): return
  358. throws(a.tags, e, comesFrom)
  359. proc addNotTag(a: PEffects, e, comesFrom: PNode) =
  360. var aa = a.forbids
  361. for i in 0..<aa.len:
  362. if sameType(aa[i].typ.skipTypes(skipPtrs), e.typ.skipTypes(skipPtrs)): return
  363. throws(a.forbids, e, comesFrom)
  364. proc mergeRaises(a: PEffects, b, comesFrom: PNode) =
  365. if b.isNil:
  366. addRaiseEffect(a, createRaise(a.graph, comesFrom), comesFrom)
  367. else:
  368. for effect in items(b): addRaiseEffect(a, effect, comesFrom)
  369. proc mergeTags(a: PEffects, b, comesFrom: PNode) =
  370. if b.isNil:
  371. addTag(a, createTag(a.graph, comesFrom), comesFrom)
  372. else:
  373. for effect in items(b): addTag(a, effect, comesFrom)
  374. proc listEffects(a: PEffects) =
  375. for e in items(a.exc): message(a.config, e.info, hintUser, typeToString(e.typ))
  376. for e in items(a.tags): message(a.config, e.info, hintUser, typeToString(e.typ))
  377. for e in items(a.forbids): message(a.config, e.info, hintUser, typeToString(e.typ))
  378. proc catches(tracked: PEffects, e: PType) =
  379. let e = skipTypes(e, skipPtrs)
  380. var L = tracked.exc.len
  381. var i = tracked.bottom
  382. while i < L:
  383. # r supertype of e?
  384. if safeInheritanceDiff(tracked.graph.excType(tracked.exc[i]), e) <= 0:
  385. tracked.exc[i] = tracked.exc[L-1]
  386. dec L
  387. else:
  388. inc i
  389. if tracked.exc.len > 0:
  390. setLen(tracked.exc.sons, L)
  391. else:
  392. assert L == 0
  393. proc catchesAll(tracked: PEffects) =
  394. if tracked.exc.len > 0:
  395. setLen(tracked.exc.sons, tracked.bottom)
  396. proc track(tracked: PEffects, n: PNode)
  397. proc trackTryStmt(tracked: PEffects, n: PNode) =
  398. let oldBottom = tracked.bottom
  399. tracked.bottom = tracked.exc.len
  400. let oldState = tracked.init.len
  401. var inter: TIntersection = @[]
  402. inc tracked.inTryStmt
  403. track(tracked, n[0])
  404. dec tracked.inTryStmt
  405. for i in oldState..<tracked.init.len:
  406. addToIntersection(inter, tracked.init[i])
  407. var branches = 1
  408. var hasFinally = false
  409. inc tracked.inExceptOrFinallyStmt
  410. # Collect the exceptions caught by the except branches
  411. for i in 1..<n.len:
  412. let b = n[i]
  413. if b.kind == nkExceptBranch:
  414. inc branches
  415. if b.len == 1:
  416. catchesAll(tracked)
  417. else:
  418. for j in 0..<b.len - 1:
  419. if b[j].isInfixAs():
  420. assert(b[j][1].kind == nkType)
  421. catches(tracked, b[j][1].typ)
  422. createTypeBoundOps(tracked, b[j][2].typ, b[j][2].info)
  423. else:
  424. assert(b[j].kind == nkType)
  425. catches(tracked, b[j].typ)
  426. else:
  427. assert b.kind == nkFinally
  428. # Add any other exception raised in the except bodies
  429. for i in 1..<n.len:
  430. let b = n[i]
  431. if b.kind == nkExceptBranch:
  432. setLen(tracked.init, oldState)
  433. for j in 0..<b.len - 1:
  434. if b[j].isInfixAs(): # skips initialization checks
  435. assert(b[j][2].kind == nkSym)
  436. tracked.init.add b[j][2].sym.id
  437. track(tracked, b[^1])
  438. for i in oldState..<tracked.init.len:
  439. addToIntersection(inter, tracked.init[i])
  440. else:
  441. setLen(tracked.init, oldState)
  442. track(tracked, b[^1])
  443. hasFinally = true
  444. tracked.bottom = oldBottom
  445. dec tracked.inExceptOrFinallyStmt
  446. if not hasFinally:
  447. setLen(tracked.init, oldState)
  448. for id, count in items(inter):
  449. if count == branches: tracked.init.add id
  450. proc isIndirectCall(tracked: PEffects; n: PNode): bool =
  451. # we don't count f(...) as an indirect call if 'f' is an parameter.
  452. # Instead we track expressions of type tyProc too. See the manual for
  453. # details:
  454. if n.kind != nkSym:
  455. result = true
  456. elif n.sym.kind == skParam:
  457. if laxEffects notin tracked.c.config.legacyFeatures:
  458. if tracked.owner == n.sym.owner and sfEffectsDelayed in n.sym.flags:
  459. result = false # it is not a harmful call
  460. else:
  461. result = true
  462. else:
  463. result = tracked.owner != n.sym.owner or tracked.owner == nil
  464. elif n.sym.kind notin routineKinds:
  465. result = true
  466. proc isForwardedProc(n: PNode): bool =
  467. result = n.kind == nkSym and sfForward in n.sym.flags
  468. proc trackPragmaStmt(tracked: PEffects, n: PNode) =
  469. for i in 0..<n.len:
  470. var it = n[i]
  471. let pragma = whichPragma(it)
  472. if pragma == wEffects:
  473. # list the computed effects up to here:
  474. listEffects(tracked)
  475. template notGcSafe(t): untyped = {tfGcSafe, tfNoSideEffect} * t.flags == {}
  476. proc importedFromC(n: PNode): bool =
  477. # when imported from C, we assume GC-safety.
  478. result = n.kind == nkSym and sfImportc in n.sym.flags
  479. proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
  480. let pragma = s.ast[pragmasPos]
  481. let spec = effectSpec(pragma, wRaises)
  482. mergeRaises(tracked, spec, n)
  483. let tagSpec = effectSpec(pragma, wTags)
  484. mergeTags(tracked, tagSpec, n)
  485. if notGcSafe(s.typ) and sfImportc notin s.flags:
  486. if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config)
  487. markGcUnsafe(tracked, s)
  488. if tfNoSideEffect notin s.typ.flags:
  489. markSideEffect(tracked, s, n.info)
  490. proc procVarCheck(n: PNode; conf: ConfigRef) =
  491. if n.kind in nkSymChoices:
  492. for x in n: procVarCheck(x, conf)
  493. elif n.kind == nkSym and n.sym.magic != mNone and n.sym.kind in routineKinds:
  494. localError(conf, n.info, ("'$1' is a built-in and cannot be used as " &
  495. "a first-class procedure") % n.sym.name.s)
  496. proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
  497. let n = n.skipConv
  498. if paramType.isNil or paramType.kind != tyTypeDesc:
  499. procVarCheck skipConvCastAndClosure(n), tracked.config
  500. #elif n.kind in nkSymChoices:
  501. # echo "came here"
  502. let paramType = paramType.skipTypesOrNil(abstractInst)
  503. if paramType != nil and tfNotNil in paramType.flags and n.typ != nil:
  504. let ntyp = n.typ.skipTypesOrNil({tyVar, tyLent, tySink})
  505. if ntyp != nil and tfNotNil notin ntyp.flags:
  506. if isAddrNode(n):
  507. # addr(x[]) can't be proven, but addr(x) can:
  508. if not containsNode(n, {nkDerefExpr, nkHiddenDeref}): return
  509. elif (n.kind == nkSym and n.sym.kind in routineKinds) or
  510. (n.kind in procDefs+{nkObjConstr, nkBracket, nkClosure, nkStrLit..nkTripleStrLit}) or
  511. (n.kind in nkCallKinds and n[0].kind == nkSym and n[0].sym.magic == mArrToSeq) or
  512. n.typ.kind == tyTypeDesc:
  513. # 'p' is not nil obviously:
  514. return
  515. case impliesNotNil(tracked.guards, n)
  516. of impUnknown:
  517. message(tracked.config, n.info, errGenerated,
  518. "cannot prove '$1' is not nil" % n.renderTree)
  519. of impNo:
  520. message(tracked.config, n.info, errGenerated,
  521. "'$1' is provably nil" % n.renderTree)
  522. of impYes: discard
  523. proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) =
  524. addRaiseEffect(tracked, createRaise(tracked.graph, n), nil)
  525. addTag(tracked, createTag(tracked.graph, n), nil)
  526. proc isOwnedProcVar(tracked: PEffects; n: PNode): bool =
  527. # XXX prove the soundness of this effect system rule
  528. result = n.kind == nkSym and n.sym.kind == skParam and
  529. tracked.owner == n.sym.owner
  530. #if result and sfPolymorphic notin n.sym.flags:
  531. # echo tracked.config $ n.info, " different here!"
  532. if laxEffects notin tracked.c.config.legacyFeatures:
  533. result = result and sfEffectsDelayed in n.sym.flags
  534. proc isNoEffectList(n: PNode): bool {.inline.} =
  535. assert n.kind == nkEffectList
  536. n.len == 0 or (n[tagEffects] == nil and n[exceptionEffects] == nil and n[forbiddenEffects] == nil)
  537. proc isTrival(caller: PNode): bool {.inline.} =
  538. result = caller.kind == nkSym and caller.sym.magic in {mEqProc, mIsNil, mMove, mWasMoved, mSwap}
  539. proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, formals: PType; argIndex: int; caller: PNode) =
  540. let a = skipConvCastAndClosure(n)
  541. let op = a.typ
  542. let param = if formals != nil and argIndex < formals.len and formals.n != nil: formals.n[argIndex].sym else: nil
  543. # assume indirect calls are taken here:
  544. if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit and
  545. not isTrival(caller) and
  546. ((param != nil and sfEffectsDelayed in param.flags) or laxEffects in tracked.c.config.legacyFeatures):
  547. internalAssert tracked.config, op.n[0].kind == nkEffectList
  548. var effectList = op.n[0]
  549. var s = n.skipConv
  550. if s.kind == nkCast and s[1].typ.kind == tyProc:
  551. s = s[1]
  552. if s.kind == nkSym and s.sym.kind in routineKinds and isNoEffectList(effectList):
  553. propagateEffects(tracked, n, s.sym)
  554. elif isNoEffectList(effectList):
  555. if isForwardedProc(n):
  556. # we have no explicit effects but it's a forward declaration and so it's
  557. # stated there are no additional effects, so simply propagate them:
  558. propagateEffects(tracked, n, n.sym)
  559. elif not isOwnedProcVar(tracked, a):
  560. # we have no explicit effects so assume the worst:
  561. assumeTheWorst(tracked, n, op)
  562. # assume GcUnsafe unless in its type; 'forward' does not matter:
  563. if notGcSafe(op) and not isOwnedProcVar(tracked, a):
  564. if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config)
  565. markGcUnsafe(tracked, a)
  566. elif tfNoSideEffect notin op.flags and not isOwnedProcVar(tracked, a):
  567. markSideEffect(tracked, a, n.info)
  568. else:
  569. mergeRaises(tracked, effectList[exceptionEffects], n)
  570. mergeTags(tracked, effectList[tagEffects], n)
  571. if notGcSafe(op):
  572. if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config)
  573. markGcUnsafe(tracked, a)
  574. elif tfNoSideEffect notin op.flags:
  575. markSideEffect(tracked, a, n.info)
  576. let paramType = if formals != nil and argIndex < formals.len: formals[argIndex] else: nil
  577. if paramType != nil and paramType.kind in {tyVar}:
  578. invalidateFacts(tracked.guards, n)
  579. if n.kind == nkSym and isLocalSym(tracked, n.sym):
  580. makeVolatile(tracked, n.sym)
  581. if paramType != nil and paramType.kind == tyProc and tfGcSafe in paramType.flags:
  582. let argtype = skipTypes(a.typ, abstractInst)
  583. # XXX figure out why this can be a non tyProc here. See httpclient.nim for an
  584. # example that triggers it.
  585. if argtype.kind == tyProc and notGcSafe(argtype) and not tracked.inEnforcedGcSafe:
  586. localError(tracked.config, n.info, $n & " is not GC safe")
  587. notNilCheck(tracked, n, paramType)
  588. proc breaksBlock(n: PNode): bool =
  589. # semantic check doesn't allow statements after raise, break, return or
  590. # call to noreturn proc, so it is safe to check just the last statements
  591. var it = n
  592. while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
  593. it = it.lastSon
  594. result = it.kind in {nkBreakStmt, nkReturnStmt, nkRaiseStmt} or
  595. it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
  596. proc trackCase(tracked: PEffects, n: PNode) =
  597. track(tracked, n[0])
  598. inc tracked.inIfStmt
  599. let oldState = tracked.init.len
  600. let oldFacts = tracked.guards.s.len
  601. let stringCase = n[0].typ != nil and skipTypes(n[0].typ,
  602. abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString, tyCstring}
  603. let interesting = not stringCase and interestingCaseExpr(n[0]) and
  604. (tracked.config.hasWarn(warnProveField) or strictCaseObjects in tracked.c.features)
  605. var inter: TIntersection = @[]
  606. var toCover = 0
  607. for i in 1..<n.len:
  608. let branch = n[i]
  609. setLen(tracked.init, oldState)
  610. if interesting:
  611. setLen(tracked.guards.s, oldFacts)
  612. addCaseBranchFacts(tracked.guards, n, i)
  613. for i in 0..<branch.len:
  614. track(tracked, branch[i])
  615. if not breaksBlock(branch.lastSon): inc toCover
  616. for i in oldState..<tracked.init.len:
  617. addToIntersection(inter, tracked.init[i])
  618. setLen(tracked.init, oldState)
  619. if not stringCase or lastSon(n).kind == nkElse:
  620. for id, count in items(inter):
  621. if count >= toCover: tracked.init.add id
  622. # else we can't merge
  623. setLen(tracked.guards.s, oldFacts)
  624. dec tracked.inIfStmt
  625. proc trackIf(tracked: PEffects, n: PNode) =
  626. track(tracked, n[0][0])
  627. inc tracked.inIfStmt
  628. let oldFacts = tracked.guards.s.len
  629. addFact(tracked.guards, n[0][0])
  630. let oldState = tracked.init.len
  631. var inter: TIntersection = @[]
  632. var toCover = 0
  633. track(tracked, n[0][1])
  634. if not breaksBlock(n[0][1]): inc toCover
  635. for i in oldState..<tracked.init.len:
  636. addToIntersection(inter, tracked.init[i])
  637. for i in 1..<n.len:
  638. let branch = n[i]
  639. setLen(tracked.guards.s, oldFacts)
  640. for j in 0..i-1:
  641. addFactNeg(tracked.guards, n[j][0])
  642. if branch.len > 1:
  643. addFact(tracked.guards, branch[0])
  644. setLen(tracked.init, oldState)
  645. for i in 0..<branch.len:
  646. track(tracked, branch[i])
  647. if not breaksBlock(branch.lastSon): inc toCover
  648. for i in oldState..<tracked.init.len:
  649. addToIntersection(inter, tracked.init[i])
  650. setLen(tracked.init, oldState)
  651. if lastSon(n).len == 1:
  652. for id, count in items(inter):
  653. if count >= toCover: tracked.init.add id
  654. # else we can't merge as it is not exhaustive
  655. setLen(tracked.guards.s, oldFacts)
  656. dec tracked.inIfStmt
  657. proc trackBlock(tracked: PEffects, n: PNode) =
  658. if n.kind in {nkStmtList, nkStmtListExpr}:
  659. var oldState = -1
  660. for i in 0..<n.len:
  661. if hasSubnodeWith(n[i], nkBreakStmt):
  662. # block:
  663. # x = def
  664. # if ...: ... break # some nested break
  665. # y = def
  666. # --> 'y' not defined after block!
  667. if oldState < 0: oldState = tracked.init.len
  668. track(tracked, n[i])
  669. if oldState > 0: setLen(tracked.init, oldState)
  670. else:
  671. track(tracked, n)
  672. proc cstringCheck(tracked: PEffects; n: PNode) =
  673. if n[0].typ.kind == tyCstring and (let a = skipConv(n[1]);
  674. a.typ.kind == tyString and a.kind notin {nkStrLit..nkTripleStrLit}):
  675. message(tracked.config, n.info, warnUnsafeCode, renderTree(n))
  676. proc patchResult(c: PEffects; n: PNode) =
  677. if n.kind == nkSym and n.sym.kind == skResult:
  678. let fn = c.owner
  679. if fn != nil and fn.kind in routineKinds and fn.ast != nil and resultPos < fn.ast.len:
  680. n.sym = fn.ast[resultPos].sym
  681. else:
  682. localError(c.config, n.info, "routine has no return type, but .requires contains 'result'")
  683. else:
  684. for i in 0..<safeLen(n):
  685. patchResult(c, n[i])
  686. proc checkLe(c: PEffects; a, b: PNode) =
  687. case proveLe(c.guards, a, b)
  688. of impUnknown:
  689. #for g in c.guards.s:
  690. # if g != nil: echo "I Know ", g
  691. message(c.config, a.info, warnStaticIndexCheck,
  692. "cannot prove: " & $a & " <= " & $b)
  693. of impYes:
  694. discard
  695. of impNo:
  696. message(c.config, a.info, warnStaticIndexCheck,
  697. "can prove: " & $a & " > " & $b)
  698. proc checkBounds(c: PEffects; arr, idx: PNode) =
  699. checkLe(c, lowBound(c.config, arr), idx)
  700. checkLe(c, idx, highBound(c.config, arr, c.guards.g.operators))
  701. proc checkRange(c: PEffects; value: PNode; typ: PType) =
  702. let t = typ.skipTypes(abstractInst - {tyRange})
  703. if t.kind == tyRange:
  704. let lowBound = copyTree(t.n[0])
  705. lowBound.info = value.info
  706. let highBound = copyTree(t.n[1])
  707. highBound.info = value.info
  708. checkLe(c, lowBound, value)
  709. checkLe(c, value, highBound)
  710. #[
  711. proc passedToEffectsDelayedParam(tracked: PEffects; n: PNode) =
  712. let t = n.typ.skipTypes(abstractInst)
  713. if t.kind == tyProc:
  714. if n.kind == nkSym and tracked.owner == n.sym.owner and sfEffectsDelayed in n.sym.flags:
  715. discard "the arg is itself a delayed parameter, so do nothing"
  716. else:
  717. var effectList = t.n[0]
  718. if effectList.len == effectListLen:
  719. mergeRaises(tracked, effectList[exceptionEffects], n)
  720. mergeTags(tracked, effectList[tagEffects], n)
  721. if not importedFromC(n):
  722. if notGcSafe(t):
  723. if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config)
  724. markGcUnsafe(tracked, n)
  725. if tfNoSideEffect notin t.flags:
  726. markSideEffect(tracked, n, n.info)
  727. ]#
  728. proc checkForSink(tracked: PEffects; n: PNode) =
  729. if tracked.inIfStmt == 0 and optSinkInference in tracked.config.options:
  730. checkForSink(tracked.config, tracked.c.idgen, tracked.owner, n)
  731. proc trackCall(tracked: PEffects; n: PNode) =
  732. template gcsafeAndSideeffectCheck() =
  733. if notGcSafe(op) and not importedFromC(a):
  734. # and it's not a recursive call:
  735. if not (a.kind == nkSym and a.sym == tracked.owner):
  736. if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config)
  737. markGcUnsafe(tracked, a)
  738. if tfNoSideEffect notin op.flags and not importedFromC(a):
  739. # and it's not a recursive call:
  740. if not (a.kind == nkSym and a.sym == tracked.owner):
  741. markSideEffect(tracked, a, n.info)
  742. # p's effects are ours too:
  743. var a = n[0]
  744. #if canRaise(a):
  745. # echo "this can raise ", tracked.config $ n.info
  746. let op = a.typ
  747. if n.typ != nil:
  748. if tracked.owner.kind != skMacro and n.typ.skipTypes(abstractVar).kind != tyOpenArray:
  749. createTypeBoundOps(tracked, n.typ, n.info)
  750. if getConstExpr(tracked.ownerModule, n, tracked.c.idgen, tracked.graph) == nil:
  751. if a.kind == nkCast and a[1].typ.kind == tyProc:
  752. a = a[1]
  753. # XXX: in rare situations, templates and macros will reach here after
  754. # calling getAst(templateOrMacro()). Currently, templates and macros
  755. # are indistinguishable from normal procs (both have tyProc type) and
  756. # we can detect them only by checking for attached nkEffectList.
  757. if op != nil and op.kind == tyProc and op.n[0].kind == nkEffectList:
  758. if a.kind == nkSym:
  759. if a.sym == tracked.owner: tracked.isRecursive = true
  760. # even for recursive calls we need to check the lock levels (!):
  761. if sfSideEffect in a.sym.flags: markSideEffect(tracked, a, n.info)
  762. else:
  763. discard
  764. var effectList = op.n[0]
  765. if a.kind == nkSym and a.sym.kind == skMethod:
  766. if {sfBase, sfThread} * a.sym.flags == {sfBase}:
  767. if tracked.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n, tracked.config)
  768. markGcUnsafe(tracked, a)
  769. propagateEffects(tracked, n, a.sym)
  770. elif isNoEffectList(effectList):
  771. if isForwardedProc(a):
  772. propagateEffects(tracked, n, a.sym)
  773. elif isIndirectCall(tracked, a):
  774. assumeTheWorst(tracked, n, op)
  775. gcsafeAndSideeffectCheck()
  776. else:
  777. if laxEffects notin tracked.c.config.legacyFeatures and a.kind == nkSym and
  778. a.sym.kind in routineKinds:
  779. propagateEffects(tracked, n, a.sym)
  780. else:
  781. mergeRaises(tracked, effectList[exceptionEffects], n)
  782. mergeTags(tracked, effectList[tagEffects], n)
  783. gcsafeAndSideeffectCheck()
  784. if a.kind != nkSym or a.sym.magic notin {mNBindSym, mFinished, mExpandToAst, mQuoteAst}:
  785. for i in 1..<n.len:
  786. trackOperandForIndirectCall(tracked, n[i], op, i, a)
  787. if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
  788. # may not look like an assignment, but it is:
  789. let arg = n[1]
  790. initVarViaNew(tracked, arg)
  791. if arg.typ.len != 0 and {tfRequiresInit} * arg.typ.lastSon.flags != {}:
  792. if a.sym.magic == mNewSeq and n[2].kind in {nkCharLit..nkUInt64Lit} and
  793. n[2].intVal == 0:
  794. # var s: seq[notnil]; newSeq(s, 0) is a special case!
  795. discard
  796. else:
  797. message(tracked.config, arg.info, warnProveInit, $arg)
  798. # check required for 'nim check':
  799. if n[1].typ.len > 0:
  800. createTypeBoundOps(tracked, n[1].typ.lastSon, n.info)
  801. createTypeBoundOps(tracked, n[1].typ, n.info)
  802. # new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'?
  803. elif a.kind == nkSym and a.sym.magic in {mArrGet, mArrPut} and
  804. optStaticBoundsCheck in tracked.currOptions:
  805. checkBounds(tracked, n[1], n[2])
  806. if a.kind != nkSym or a.sym.magic notin {mRunnableExamples, mNBindSym, mExpandToAst, mQuoteAst}:
  807. for i in 0..<n.safeLen:
  808. track(tracked, n[i])
  809. if a.kind == nkSym and a.sym.name.s.len > 0 and a.sym.name.s[0] == '=' and
  810. tracked.owner.kind != skMacro:
  811. var opKind = find(AttachedOpToStr, a.sym.name.s.normalize)
  812. if a.sym.name.s == "=": opKind = attachedAsgn.int
  813. if opKind != -1:
  814. # rebind type bounds operations after createTypeBoundOps call
  815. let t = n[1].typ.skipTypes({tyAlias, tyVar})
  816. if a.sym != getAttachedOp(tracked.graph, t, TTypeAttachedOp(opKind)):
  817. createTypeBoundOps(tracked, t, n.info)
  818. let op = getAttachedOp(tracked.graph, t, TTypeAttachedOp(opKind))
  819. if op != nil:
  820. n[0].sym = op
  821. if op != nil and op.kind == tyProc:
  822. for i in 1..<min(n.safeLen, op.len):
  823. let paramType = op[i]
  824. case paramType.kind
  825. of tySink:
  826. createTypeBoundOps(tracked, paramType[0], n.info)
  827. checkForSink(tracked, n[i])
  828. of tyVar:
  829. if isOutParam(paramType):
  830. # consider this case: p(out x, x); we want to remark that 'x' is not
  831. # initialized until after the call. Since we do this after we analysed the
  832. # call, this is fine.
  833. initVar(tracked, n[i].skipAddr, false)
  834. if strictFuncs in tracked.c.features and not tracked.inEnforcedNoSideEffects and
  835. isDangerousLocation(n[i].skipAddr, tracked.owner):
  836. if sfNoSideEffect in tracked.owner.flags:
  837. localError(tracked.config, n[i].info,
  838. "cannot pass $1 to `var T` parameter within a strict func" % renderTree(n[i]))
  839. tracked.hasSideEffect = true
  840. else: discard
  841. type
  842. PragmaBlockContext = object
  843. oldLocked: int
  844. enforcedGcSafety, enforceNoSideEffects: bool
  845. oldExc, oldTags, oldForbids: int
  846. exc, tags, forbids: PNode
  847. proc createBlockContext(tracked: PEffects): PragmaBlockContext =
  848. var oldForbidsLen = 0
  849. if tracked.forbids != nil: oldForbidsLen = tracked.forbids.len
  850. result = PragmaBlockContext(oldLocked: tracked.locked.len,
  851. enforcedGcSafety: false, enforceNoSideEffects: false,
  852. oldExc: tracked.exc.len, oldTags: tracked.tags.len,
  853. oldForbids: oldForbidsLen)
  854. proc applyBlockContext(tracked: PEffects, bc: PragmaBlockContext) =
  855. if bc.enforcedGcSafety: tracked.inEnforcedGcSafe = true
  856. if bc.enforceNoSideEffects: tracked.inEnforcedNoSideEffects = true
  857. proc unapplyBlockContext(tracked: PEffects; bc: PragmaBlockContext) =
  858. if bc.enforcedGcSafety: tracked.inEnforcedGcSafe = false
  859. if bc.enforceNoSideEffects: tracked.inEnforcedNoSideEffects = false
  860. setLen(tracked.locked, bc.oldLocked)
  861. if bc.exc != nil:
  862. # beware that 'raises: []' is very different from not saying
  863. # anything about 'raises' in the 'cast' at all. Same applies for 'tags'.
  864. setLen(tracked.exc.sons, bc.oldExc)
  865. for e in bc.exc:
  866. addRaiseEffect(tracked, e, e)
  867. if bc.tags != nil:
  868. setLen(tracked.tags.sons, bc.oldTags)
  869. for t in bc.tags:
  870. addTag(tracked, t, t)
  871. if bc.forbids != nil:
  872. setLen(tracked.forbids.sons, bc.oldForbids)
  873. for t in bc.forbids:
  874. addNotTag(tracked, t, t)
  875. proc castBlock(tracked: PEffects, pragma: PNode, bc: var PragmaBlockContext) =
  876. case whichPragma(pragma)
  877. of wGcSafe:
  878. bc.enforcedGcSafety = true
  879. of wNoSideEffect:
  880. bc.enforceNoSideEffects = true
  881. of wTags:
  882. let n = pragma[1]
  883. if n.kind in {nkCurly, nkBracket}:
  884. bc.tags = n
  885. else:
  886. bc.tags = newNodeI(nkArgList, pragma.info)
  887. bc.tags.add n
  888. of wForbids:
  889. let n = pragma[1]
  890. if n.kind in {nkCurly, nkBracket}:
  891. bc.forbids = n
  892. else:
  893. bc.forbids = newNodeI(nkArgList, pragma.info)
  894. bc.forbids.add n
  895. of wRaises:
  896. let n = pragma[1]
  897. if n.kind in {nkCurly, nkBracket}:
  898. bc.exc = n
  899. else:
  900. bc.exc = newNodeI(nkArgList, pragma.info)
  901. bc.exc.add n
  902. of wUncheckedAssign:
  903. discard "handled in sempass1"
  904. else:
  905. localError(tracked.config, pragma.info,
  906. "invalid pragma block: " & $pragma)
  907. proc trackInnerProc(tracked: PEffects, n: PNode) =
  908. case n.kind
  909. of nkSym:
  910. let s = n.sym
  911. if s.kind == skParam and s.owner == tracked.owner:
  912. tracked.escapingParams.incl s.id
  913. of nkNone..pred(nkSym), succ(nkSym)..nkNilLit:
  914. discard
  915. of nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkLambda, nkFuncDef, nkDo:
  916. if n[0].kind == nkSym and n[0].sym.ast != nil:
  917. trackInnerProc(tracked, getBody(tracked.graph, n[0].sym))
  918. of nkTypeSection, nkMacroDef, nkTemplateDef, nkError,
  919. nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
  920. nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
  921. nkTypeOfExpr, nkMixinStmt, nkBindStmt:
  922. discard
  923. else:
  924. for ch in n: trackInnerProc(tracked, ch)
  925. proc allowCStringConv(n: PNode): bool =
  926. case n.kind
  927. of nkStrLit..nkTripleStrLit: result = true
  928. of nkSym: result = n.sym.kind in {skConst, skParam}
  929. of nkAddr: result = isCharArrayPtr(n.typ, true)
  930. of nkCallKinds:
  931. result = isCharArrayPtr(n.typ, n[0].kind == nkSym and n[0].sym.magic == mAddr)
  932. else: result = isCharArrayPtr(n.typ, false)
  933. proc track(tracked: PEffects, n: PNode) =
  934. case n.kind
  935. of nkSym:
  936. useVar(tracked, n)
  937. if n.sym.typ != nil and tfHasAsgn in n.sym.typ.flags:
  938. tracked.owner.flags.incl sfInjectDestructors
  939. # bug #15038: ensure consistency
  940. if not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ): n.typ = n.sym.typ
  941. of nkHiddenAddr, nkAddr:
  942. if n[0].kind == nkSym and isLocalSym(tracked, n[0].sym):
  943. useVarNoInitCheck(tracked, n[0], n[0].sym)
  944. else:
  945. track(tracked, n[0])
  946. of nkRaiseStmt:
  947. if n[0].kind != nkEmpty:
  948. n[0].info = n.info
  949. #throws(tracked.exc, n[0])
  950. addRaiseEffect(tracked, n[0], n)
  951. for i in 0..<n.safeLen:
  952. track(tracked, n[i])
  953. createTypeBoundOps(tracked, n[0].typ, n.info)
  954. else:
  955. # A `raise` with no arguments means we're going to re-raise the exception
  956. # being handled or, if outside of an `except` block, a `ReraiseDefect`.
  957. # Here we add a `Exception` tag in order to cover both the cases.
  958. addRaiseEffect(tracked, createRaise(tracked.graph, n), nil)
  959. of nkCallKinds:
  960. trackCall(tracked, n)
  961. of nkDotExpr:
  962. guardDotAccess(tracked, n)
  963. for i in 0..<n.len: track(tracked, n[i])
  964. of nkCheckedFieldExpr:
  965. track(tracked, n[0])
  966. if tracked.config.hasWarn(warnProveField) or strictCaseObjects in tracked.c.features:
  967. checkFieldAccess(tracked.guards, n, tracked.config, strictCaseObjects in tracked.c.features)
  968. of nkTryStmt: trackTryStmt(tracked, n)
  969. of nkPragma: trackPragmaStmt(tracked, n)
  970. of nkAsgn, nkFastAsgn, nkSinkAsgn:
  971. track(tracked, n[1])
  972. initVar(tracked, n[0], volatileCheck=true)
  973. invalidateFacts(tracked.guards, n[0])
  974. inc tracked.leftPartOfAsgn
  975. track(tracked, n[0])
  976. dec tracked.leftPartOfAsgn
  977. addAsgnFact(tracked.guards, n[0], n[1])
  978. notNilCheck(tracked, n[1], n[0].typ)
  979. when false: cstringCheck(tracked, n)
  980. if tracked.owner.kind != skMacro and n[0].typ.kind notin {tyOpenArray, tyVarargs}:
  981. createTypeBoundOps(tracked, n[0].typ, n.info)
  982. if n[0].kind != nkSym or not isLocalSym(tracked, n[0].sym):
  983. checkForSink(tracked, n[1])
  984. if strictFuncs in tracked.c.features and not tracked.inEnforcedNoSideEffects and
  985. isDangerousLocation(n[0], tracked.owner):
  986. tracked.hasSideEffect = true
  987. if sfNoSideEffect in tracked.owner.flags:
  988. localError(tracked.config, n[0].info,
  989. "cannot mutate location $1 within a strict func" % renderTree(n[0]))
  990. of nkVarSection, nkLetSection:
  991. for child in n:
  992. let last = lastSon(child)
  993. if last.kind != nkEmpty: track(tracked, last)
  994. if tracked.owner.kind != skMacro:
  995. if child.kind == nkVarTuple:
  996. createTypeBoundOps(tracked, child[^1].typ, child.info)
  997. for i in 0..<child.len-2:
  998. createTypeBoundOps(tracked, child[i].typ, child.info)
  999. else:
  1000. createTypeBoundOps(tracked, skipPragmaExpr(child[0]).typ, child.info)
  1001. if child.kind == nkIdentDefs:
  1002. for i in 0..<child.len-2:
  1003. let a = skipPragmaExpr(child[i])
  1004. varDecl(tracked, a)
  1005. if last.kind != nkEmpty:
  1006. initVar(tracked, a, volatileCheck=false)
  1007. addAsgnFact(tracked.guards, a, last)
  1008. notNilCheck(tracked, last, a.typ)
  1009. elif child.kind == nkVarTuple:
  1010. for i in 0..<child.len-1:
  1011. if child[i].kind == nkEmpty or
  1012. child[i].kind == nkSym and child[i].sym.name.id == ord(wUnderscore):
  1013. continue
  1014. varDecl(tracked, child[i])
  1015. if last.kind != nkEmpty:
  1016. initVar(tracked, child[i], volatileCheck=false)
  1017. if last.kind in {nkPar, nkTupleConstr}:
  1018. addAsgnFact(tracked.guards, child[i], last[i])
  1019. notNilCheck(tracked, last[i], child[i].typ)
  1020. # since 'var (a, b): T = ()' is not even allowed, there is always type
  1021. # inference for (a, b) and thus no nil checking is necessary.
  1022. of nkConstSection:
  1023. for child in n:
  1024. let last = lastSon(child)
  1025. track(tracked, last)
  1026. of nkCaseStmt: trackCase(tracked, n)
  1027. of nkWhen, nkIfStmt, nkIfExpr: trackIf(tracked, n)
  1028. of nkBlockStmt, nkBlockExpr: trackBlock(tracked, n[1])
  1029. of nkWhileStmt:
  1030. # 'while true' loop?
  1031. inc tracked.currentBlock
  1032. if isTrue(n[0]):
  1033. trackBlock(tracked, n[1])
  1034. else:
  1035. # loop may never execute:
  1036. let oldState = tracked.init.len
  1037. let oldFacts = tracked.guards.s.len
  1038. addFact(tracked.guards, n[0])
  1039. track(tracked, n[0])
  1040. track(tracked, n[1])
  1041. setLen(tracked.init, oldState)
  1042. setLen(tracked.guards.s, oldFacts)
  1043. dec tracked.currentBlock
  1044. of nkForStmt, nkParForStmt:
  1045. # we are very conservative here and assume the loop is never executed:
  1046. inc tracked.currentBlock
  1047. let oldState = tracked.init.len
  1048. let oldFacts = tracked.guards.s.len
  1049. let iterCall = n[n.len-2]
  1050. if optStaticBoundsCheck in tracked.currOptions and iterCall.kind in nkCallKinds:
  1051. let op = iterCall[0]
  1052. if op.kind == nkSym and fromSystem(op.sym):
  1053. let iterVar = n[0]
  1054. case op.sym.name.s
  1055. of "..", "countup", "countdown":
  1056. let lower = iterCall[1]
  1057. let upper = iterCall[2]
  1058. # for i in 0..n means 0 <= i and i <= n. Countdown is
  1059. # the same since only the iteration direction changes.
  1060. addFactLe(tracked.guards, lower, iterVar)
  1061. addFactLe(tracked.guards, iterVar, upper)
  1062. of "..<":
  1063. let lower = iterCall[1]
  1064. let upper = iterCall[2]
  1065. addFactLe(tracked.guards, lower, iterVar)
  1066. addFactLt(tracked.guards, iterVar, upper)
  1067. else: discard
  1068. for i in 0..<n.len-2:
  1069. let it = n[i]
  1070. track(tracked, it)
  1071. if tracked.owner.kind != skMacro:
  1072. if it.kind == nkVarTuple:
  1073. for x in it:
  1074. createTypeBoundOps(tracked, x.typ, x.info)
  1075. else:
  1076. createTypeBoundOps(tracked, it.typ, it.info)
  1077. let loopBody = n[^1]
  1078. if tracked.owner.kind != skMacro and iterCall.safeLen > 1:
  1079. # XXX this is a bit hacky:
  1080. if iterCall[1].typ != nil and iterCall[1].typ.skipTypes(abstractVar).kind notin {tyVarargs, tyOpenArray}:
  1081. createTypeBoundOps(tracked, iterCall[1].typ, iterCall[1].info)
  1082. track(tracked, iterCall)
  1083. track(tracked, loopBody)
  1084. setLen(tracked.init, oldState)
  1085. setLen(tracked.guards.s, oldFacts)
  1086. dec tracked.currentBlock
  1087. of nkObjConstr:
  1088. when false: track(tracked, n[0])
  1089. let oldFacts = tracked.guards.s.len
  1090. for i in 1..<n.len:
  1091. let x = n[i]
  1092. track(tracked, x)
  1093. if x[0].kind == nkSym and sfDiscriminant in x[0].sym.flags:
  1094. addDiscriminantFact(tracked.guards, x)
  1095. if tracked.owner.kind != skMacro:
  1096. createTypeBoundOps(tracked, x[1].typ, n.info)
  1097. if x.kind == nkExprColonExpr:
  1098. if x[0].kind == nkSym:
  1099. notNilCheck(tracked, x[1], x[0].sym.typ)
  1100. checkForSink(tracked, x[1])
  1101. else:
  1102. checkForSink(tracked, x)
  1103. setLen(tracked.guards.s, oldFacts)
  1104. if tracked.owner.kind != skMacro:
  1105. # XXX n.typ can be nil in runnableExamples, we need to do something about it.
  1106. if n.typ != nil and n.typ.skipTypes(abstractInst).kind == tyRef:
  1107. createTypeBoundOps(tracked, n.typ.lastSon, n.info)
  1108. createTypeBoundOps(tracked, n.typ, n.info)
  1109. of nkTupleConstr:
  1110. for i in 0..<n.len:
  1111. track(tracked, n[i])
  1112. notNilCheck(tracked, n[i].skipColon, n[i].typ)
  1113. if tracked.owner.kind != skMacro:
  1114. if n[i].kind == nkExprColonExpr:
  1115. createTypeBoundOps(tracked, n[i][0].typ, n.info)
  1116. else:
  1117. createTypeBoundOps(tracked, n[i].typ, n.info)
  1118. checkForSink(tracked, n[i])
  1119. of nkPragmaBlock:
  1120. let pragmaList = n[0]
  1121. var bc = createBlockContext(tracked)
  1122. for i in 0..<pragmaList.len:
  1123. let pragma = whichPragma(pragmaList[i])
  1124. case pragma
  1125. of wLocks:
  1126. lockLocations(tracked, pragmaList[i])
  1127. of wGcSafe:
  1128. bc.enforcedGcSafety = true
  1129. of wNoSideEffect:
  1130. bc.enforceNoSideEffects = true
  1131. of wCast:
  1132. castBlock(tracked, pragmaList[i][1], bc)
  1133. else:
  1134. discard
  1135. applyBlockContext(tracked, bc)
  1136. track(tracked, n.lastSon)
  1137. unapplyBlockContext(tracked, bc)
  1138. of nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkLambda, nkFuncDef, nkDo:
  1139. if n[0].kind == nkSym and n[0].sym.ast != nil:
  1140. trackInnerProc(tracked, getBody(tracked.graph, n[0].sym))
  1141. of nkTypeSection, nkMacroDef, nkTemplateDef:
  1142. discard
  1143. of nkCast:
  1144. if n.len == 2:
  1145. track(tracked, n[1])
  1146. if tracked.owner.kind != skMacro:
  1147. createTypeBoundOps(tracked, n.typ, n.info)
  1148. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  1149. if n.kind in {nkHiddenStdConv, nkHiddenSubConv} and
  1150. n.typ.skipTypes(abstractInst).kind == tyCstring and
  1151. not allowCStringConv(n[1]):
  1152. message(tracked.config, n.info, warnCstringConv,
  1153. "implicit conversion to 'cstring' from a non-const location: $1; this will become a compile time error in the future" %
  1154. $n[1])
  1155. if n.typ.skipTypes(abstractInst).kind == tyCstring and
  1156. isCharArrayPtr(n[1].typ, true):
  1157. message(tracked.config, n.info, warnPtrToCstringConv,
  1158. $n[1].typ)
  1159. let t = n.typ.skipTypes(abstractInst)
  1160. if t.kind == tyEnum:
  1161. if tfEnumHasHoles in t.flags:
  1162. message(tracked.config, n.info, warnHoleEnumConv, "conversion to enum with holes is unsafe: $1" % $n)
  1163. else:
  1164. message(tracked.config, n.info, warnAnyEnumConv, "enum conversion: $1" % $n)
  1165. if n.len == 2:
  1166. track(tracked, n[1])
  1167. if tracked.owner.kind != skMacro:
  1168. createTypeBoundOps(tracked, n.typ, n.info)
  1169. # This is a hacky solution in order to fix bug #13110. Hopefully
  1170. # a better solution will come up eventually.
  1171. if n[1].typ.kind != tyString:
  1172. createTypeBoundOps(tracked, n[1].typ, n[1].info)
  1173. if optStaticBoundsCheck in tracked.currOptions:
  1174. checkRange(tracked, n[1], n.typ)
  1175. of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
  1176. if n.len == 1:
  1177. track(tracked, n[0])
  1178. if tracked.owner.kind != skMacro:
  1179. createTypeBoundOps(tracked, n.typ, n.info)
  1180. createTypeBoundOps(tracked, n[0].typ, n[0].info)
  1181. if optStaticBoundsCheck in tracked.currOptions:
  1182. checkRange(tracked, n[0], n.typ)
  1183. of nkBracket:
  1184. for i in 0..<n.safeLen:
  1185. track(tracked, n[i])
  1186. checkForSink(tracked, n[i])
  1187. if tracked.owner.kind != skMacro:
  1188. createTypeBoundOps(tracked, n.typ, n.info)
  1189. of nkBracketExpr:
  1190. if optStaticBoundsCheck in tracked.currOptions and n.len == 2:
  1191. if n[0].typ != nil and skipTypes(n[0].typ, abstractVar).kind != tyTuple:
  1192. checkBounds(tracked, n[0], n[1])
  1193. track(tracked, n[0])
  1194. dec tracked.leftPartOfAsgn
  1195. for i in 1 ..< n.len: track(tracked, n[i])
  1196. inc tracked.leftPartOfAsgn
  1197. of nkError:
  1198. localError(tracked.config, n.info, errorToString(tracked.config, n))
  1199. else:
  1200. for i in 0..<n.safeLen: track(tracked, n[i])
  1201. proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool =
  1202. if spec.typ.kind == tyOr:
  1203. for t in spec.typ.sons:
  1204. if safeInheritanceDiff(g.excType(real), t) <= 0:
  1205. return true
  1206. else:
  1207. return safeInheritanceDiff(g.excType(real), spec.typ) <= 0
  1208. proc checkRaisesSpec(g: ModuleGraph; emitWarnings: bool; spec, real: PNode, msg: string, hints: bool;
  1209. effectPredicate: proc (g: ModuleGraph; a, b: PNode): bool {.nimcall.};
  1210. hintsArg: PNode = nil; isForbids: bool = false) =
  1211. # check that any real exception is listed in 'spec'; mark those as used;
  1212. # report any unused exception
  1213. var used = initIntSet()
  1214. for r in items(real):
  1215. block search:
  1216. for s in 0..<spec.len:
  1217. if effectPredicate(g, spec[s], r):
  1218. if isForbids: break
  1219. used.incl(s)
  1220. break search
  1221. if isForbids:
  1222. break search
  1223. # XXX call graph analysis would be nice here!
  1224. pushInfoContext(g.config, spec.info)
  1225. var rr = if r.kind == nkRaiseStmt: r[0] else: r
  1226. while rr.kind in {nkStmtList, nkStmtListExpr} and rr.len > 0: rr = rr.lastSon
  1227. message(g.config, r.info, if emitWarnings: warnEffect else: errGenerated,
  1228. renderTree(rr) & " " & msg & typeToString(r.typ))
  1229. popInfoContext(g.config)
  1230. # hint about unnecessarily listed exception types:
  1231. if hints:
  1232. for s in 0..<spec.len:
  1233. if not used.contains(s):
  1234. message(g.config, spec[s].info, hintXCannotRaiseY,
  1235. "'$1' cannot raise '$2'" % [renderTree(hintsArg), renderTree(spec[s])])
  1236. proc checkMethodEffects*(g: ModuleGraph; disp, branch: PSym) =
  1237. ## checks for consistent effects for multi methods.
  1238. let actual = branch.typ.n[0]
  1239. if actual.len != effectListLen: return
  1240. let p = disp.ast[pragmasPos]
  1241. let raisesSpec = effectSpec(p, wRaises)
  1242. if not isNil(raisesSpec):
  1243. checkRaisesSpec(g, false, raisesSpec, actual[exceptionEffects],
  1244. "can raise an unlisted exception: ", hints=off, subtypeRelation)
  1245. let tagsSpec = effectSpec(p, wTags)
  1246. if not isNil(tagsSpec):
  1247. checkRaisesSpec(g, false, tagsSpec, actual[tagEffects],
  1248. "can have an unlisted effect: ", hints=off, subtypeRelation)
  1249. let forbidsSpec = effectSpec(p, wForbids)
  1250. if not isNil(forbidsSpec):
  1251. checkRaisesSpec(g, false, forbidsSpec, actual[tagEffects],
  1252. "has an illegal effect: ", hints=off, subtypeRelation, isForbids=true)
  1253. if sfThread in disp.flags and notGcSafe(branch.typ):
  1254. localError(g.config, branch.info, "base method is GC-safe, but '$1' is not" %
  1255. branch.name.s)
  1256. when defined(drnim):
  1257. if not g.compatibleProps(g, disp.typ, branch.typ):
  1258. localError(g.config, branch.info, "for method '" & branch.name.s &
  1259. "' the `.requires` or `.ensures` properties are incompatible.")
  1260. proc setEffectsForProcType*(g: ModuleGraph; t: PType, n: PNode; s: PSym = nil) =
  1261. var effects = t.n[0]
  1262. if t.kind != tyProc or effects.kind != nkEffectList: return
  1263. if n.kind != nkEmpty:
  1264. internalAssert g.config, effects.len == 0
  1265. newSeq(effects.sons, effectListLen)
  1266. let raisesSpec = effectSpec(n, wRaises)
  1267. if not isNil(raisesSpec):
  1268. effects[exceptionEffects] = raisesSpec
  1269. elif s != nil and (s.magic != mNone or {sfImportc, sfExportc} * s.flags == {sfImportc}):
  1270. effects[exceptionEffects] = newNodeI(nkArgList, effects.info)
  1271. let tagsSpec = effectSpec(n, wTags)
  1272. if not isNil(tagsSpec):
  1273. effects[tagEffects] = tagsSpec
  1274. elif s != nil and (s.magic != mNone or {sfImportc, sfExportc} * s.flags == {sfImportc}):
  1275. effects[tagEffects] = newNodeI(nkArgList, effects.info)
  1276. let forbidsSpec = effectSpec(n, wForbids)
  1277. if not isNil(forbidsSpec):
  1278. effects[forbiddenEffects] = forbidsSpec
  1279. elif s != nil and (s.magic != mNone or {sfImportc, sfExportc} * s.flags == {sfImportc}):
  1280. effects[forbiddenEffects] = newNodeI(nkArgList, effects.info)
  1281. let requiresSpec = propSpec(n, wRequires)
  1282. if not isNil(requiresSpec):
  1283. effects[requiresEffects] = requiresSpec
  1284. let ensuresSpec = propSpec(n, wEnsures)
  1285. if not isNil(ensuresSpec):
  1286. effects[ensuresEffects] = ensuresSpec
  1287. effects[pragmasEffects] = n
  1288. if s != nil and s.magic != mNone:
  1289. if s.magic != mEcho:
  1290. t.flags.incl tfNoSideEffect
  1291. proc rawInitEffects(g: ModuleGraph; effects: PNode) =
  1292. newSeq(effects.sons, effectListLen)
  1293. effects[exceptionEffects] = newNodeI(nkArgList, effects.info)
  1294. effects[tagEffects] = newNodeI(nkArgList, effects.info)
  1295. effects[forbiddenEffects] = newNodeI(nkArgList, effects.info)
  1296. effects[requiresEffects] = g.emptyNode
  1297. effects[ensuresEffects] = g.emptyNode
  1298. effects[pragmasEffects] = g.emptyNode
  1299. proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects; c: PContext) =
  1300. rawInitEffects(g, effects)
  1301. t.exc = effects[exceptionEffects]
  1302. t.tags = effects[tagEffects]
  1303. t.forbids = effects[forbiddenEffects]
  1304. t.owner = s
  1305. t.ownerModule = s.getModule
  1306. t.init = @[]
  1307. t.guards.s = @[]
  1308. t.guards.g = g
  1309. when defined(drnim):
  1310. t.currOptions = g.config.options + s.options - {optStaticBoundsCheck}
  1311. else:
  1312. t.currOptions = g.config.options + s.options
  1313. t.guards.beSmart = optStaticBoundsCheck in t.currOptions
  1314. t.locked = @[]
  1315. t.graph = g
  1316. t.config = g.config
  1317. t.c = c
  1318. t.currentBlock = 1
  1319. proc hasRealBody(s: PSym): bool =
  1320. ## also handles importc procs with runnableExamples, which requires `=`,
  1321. ## which is not a real implementation, refs #14314
  1322. result = {sfForward, sfImportc} * s.flags == {}
  1323. proc trackProc*(c: PContext; s: PSym, body: PNode) =
  1324. let g = c.graph
  1325. when defined(nimsuggest):
  1326. if g.config.expandDone():
  1327. return
  1328. var effects = s.typ.n[0]
  1329. if effects.kind != nkEffectList: return
  1330. # effects already computed?
  1331. if not s.hasRealBody: return
  1332. let emitWarnings = tfEffectSystemWorkaround in s.typ.flags
  1333. if effects.len == effectListLen and not emitWarnings: return
  1334. var inferredEffects = newNodeI(nkEffectList, s.info)
  1335. var t: TEffects
  1336. initEffects(g, inferredEffects, s, t, c)
  1337. rawInitEffects g, effects
  1338. if not isEmptyType(s.typ[0]) and
  1339. s.kind in {skProc, skFunc, skConverter, skMethod}:
  1340. var res = s.ast[resultPos].sym # get result symbol
  1341. t.scopes[res.id] = t.currentBlock
  1342. track(t, body)
  1343. if s.kind != skMacro:
  1344. let params = s.typ.n
  1345. for i in 1..<params.len:
  1346. let param = params[i].sym
  1347. let typ = param.typ
  1348. if isSinkTypeForParam(typ) or
  1349. (t.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
  1350. (isClosure(typ.skipTypes(abstractInst)) or param.id in t.escapingParams)):
  1351. createTypeBoundOps(t, typ, param.info)
  1352. if isOutParam(typ) and param.id notin t.init:
  1353. message(g.config, param.info, warnProveInit, param.name.s)
  1354. if not isEmptyType(s.typ[0]) and
  1355. (s.typ[0].requiresInit or s.typ[0].skipTypes(abstractInst).kind == tyVar or
  1356. strictDefs in c.features) and
  1357. s.kind in {skProc, skFunc, skConverter, skMethod} and s.magic == mNone:
  1358. var res = s.ast[resultPos].sym # get result symbol
  1359. if res.id notin t.init:
  1360. if tfRequiresInit in s.typ[0].flags:
  1361. localError(g.config, body.info, "'$1' requires explicit initialization" % "result")
  1362. else:
  1363. message(g.config, body.info, warnProveInit, "result")
  1364. let p = s.ast[pragmasPos]
  1365. let raisesSpec = effectSpec(p, wRaises)
  1366. if not isNil(raisesSpec):
  1367. let useWarning = s.name.s == "=destroy"
  1368. checkRaisesSpec(g, useWarning, raisesSpec, t.exc, "can raise an unlisted exception: ",
  1369. hints=on, subtypeRelation, hintsArg=s.ast[0])
  1370. # after the check, use the formal spec:
  1371. effects[exceptionEffects] = raisesSpec
  1372. else:
  1373. effects[exceptionEffects] = t.exc
  1374. let tagsSpec = effectSpec(p, wTags)
  1375. if not isNil(tagsSpec):
  1376. checkRaisesSpec(g, false, tagsSpec, t.tags, "can have an unlisted effect: ",
  1377. hints=off, subtypeRelation)
  1378. # after the check, use the formal spec:
  1379. effects[tagEffects] = tagsSpec
  1380. else:
  1381. effects[tagEffects] = t.tags
  1382. let forbidsSpec = effectSpec(p, wForbids)
  1383. if not isNil(forbidsSpec):
  1384. checkRaisesSpec(g, false, forbidsSpec, t.tags, "has an illegal effect: ",
  1385. hints=off, subtypeRelation, isForbids=true)
  1386. # after the check, use the formal spec:
  1387. effects[forbiddenEffects] = forbidsSpec
  1388. else:
  1389. effects[forbiddenEffects] = t.forbids
  1390. let requiresSpec = propSpec(p, wRequires)
  1391. if not isNil(requiresSpec):
  1392. effects[requiresEffects] = requiresSpec
  1393. let ensuresSpec = propSpec(p, wEnsures)
  1394. if not isNil(ensuresSpec):
  1395. patchResult(t, ensuresSpec)
  1396. effects[ensuresEffects] = ensuresSpec
  1397. var mutationInfo = MutationInfo()
  1398. if views in c.features:
  1399. var partitions = computeGraphPartitions(s, body, g, {borrowChecking})
  1400. checkBorrowedLocations(partitions, body, g.config)
  1401. if sfThread in s.flags and t.gcUnsafe:
  1402. if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions:
  1403. #localError(s.info, "'$1' is not GC-safe" % s.name.s)
  1404. listGcUnsafety(s, onlyWarning=false, g.config)
  1405. else:
  1406. listGcUnsafety(s, onlyWarning=true, g.config)
  1407. #localError(s.info, warnGcUnsafe2, s.name.s)
  1408. if sfNoSideEffect in s.flags and t.hasSideEffect:
  1409. when false:
  1410. listGcUnsafety(s, onlyWarning=false, g.config)
  1411. else:
  1412. if c.compilesContextId == 0: # don't render extended diagnostic messages in `system.compiles` context
  1413. var msg = ""
  1414. listSideEffects(msg, s, g.config, t.c)
  1415. message(g.config, s.info, errGenerated, msg)
  1416. else:
  1417. localError(g.config, s.info, "") # simple error for `system.compiles` context
  1418. if not t.gcUnsafe:
  1419. s.typ.flags.incl tfGcSafe
  1420. if not t.hasSideEffect and sfSideEffect notin s.flags:
  1421. s.typ.flags.incl tfNoSideEffect
  1422. when defined(drnim):
  1423. if c.graph.strongSemCheck != nil: c.graph.strongSemCheck(c.graph, s, body)
  1424. when defined(useDfa):
  1425. if s.name.s == "testp":
  1426. dataflowAnalysis(s, body)
  1427. when false: trackWrites(s, body)
  1428. if strictNotNil in c.features and s.kind == skProc:
  1429. checkNil(s, body, g.config, c.idgen)
  1430. proc trackStmt*(c: PContext; module: PSym; n: PNode, isTopLevel: bool) =
  1431. if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef,
  1432. nkTypeSection, nkConverterDef, nkMethodDef, nkIteratorDef}:
  1433. return
  1434. let g = c.graph
  1435. var effects = newNodeI(nkEffectList, n.info)
  1436. var t: TEffects
  1437. initEffects(g, effects, module, t, c)
  1438. t.isTopLevel = isTopLevel
  1439. track(t, n)
  1440. when defined(drnim):
  1441. if c.graph.strongSemCheck != nil: c.graph.strongSemCheck(c.graph, module, n)