sempass2.nim 66 KB

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