mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-20 22:35:24 +00:00
more precise analysis about 'observable stores' [backport:1.2] (#14582)
(cherry picked from commit 32083c7ff8)
This commit is contained in:
@@ -292,6 +292,7 @@ type
|
||||
sfInjectDestructors # whether the proc needs the 'injectdestructors' transformation
|
||||
sfNeverRaises # proc can never raise an exception, not even OverflowError
|
||||
# or out-of-memory
|
||||
sfUsedInFinallyOrExcept # symbol is used inside an 'except' or 'finally'
|
||||
|
||||
TSymFlags* = set[TSymFlag]
|
||||
|
||||
|
||||
@@ -22,14 +22,20 @@ proc canRaiseDisp(p: BProc; n: PNode): bool =
|
||||
result = canRaiseConservative(n)
|
||||
|
||||
proc preventNrvo(p: BProc; le, ri: PNode): bool =
|
||||
proc locationEscapes(p: BProc; le: PNode): bool =
|
||||
proc locationEscapes(p: BProc; le: PNode; inTryStmt: bool): bool =
|
||||
var n = le
|
||||
while true:
|
||||
# do NOT follow nkHiddenDeref here!
|
||||
case n.kind
|
||||
of nkSym:
|
||||
# we don't own the location so it escapes:
|
||||
return n.sym.owner != p.prc
|
||||
if n.sym.owner != p.prc:
|
||||
return true
|
||||
elif inTryStmt and sfUsedInFinallyOrExcept in n.sym.flags:
|
||||
# it is also an observable store if the location is used
|
||||
# in 'except' or 'finally'
|
||||
return true
|
||||
return false
|
||||
of nkDotExpr, nkBracketExpr, nkObjUpConv, nkObjDownConv,
|
||||
nkCheckedFieldExpr:
|
||||
n = n[0]
|
||||
@@ -46,7 +52,7 @@ proc preventNrvo(p: BProc; le, ri: PNode): bool =
|
||||
# we use the weaker 'canRaise' here in order to prevent too many
|
||||
# annoying warnings, see #14514
|
||||
if canRaise(ri[0]) and
|
||||
(p.nestedTryStmts.len > 0 or locationEscapes(p, le)):
|
||||
locationEscapes(p, le, p.nestedTryStmts.len > 0):
|
||||
message(p.config, le.info, warnObservableStores, $le)
|
||||
|
||||
proc hasNoInit(call: PNode): bool {.inline.} =
|
||||
|
||||
@@ -66,7 +66,7 @@ type
|
||||
TEffects = object
|
||||
exc: PNode # stack of exceptions
|
||||
tags: PNode # list of tags
|
||||
bottom, inTryStmt: int
|
||||
bottom, inTryStmt, inExceptOrFinallyStmt: int
|
||||
owner: PSym
|
||||
ownerModule: PSym
|
||||
init: seq[int] # list of initialized variables
|
||||
@@ -248,6 +248,8 @@ proc listGcUnsafety(s: PSym; onlyWarning: bool; conf: ConfigRef) =
|
||||
|
||||
proc useVar(a: PEffects, n: PNode) =
|
||||
let s = n.sym
|
||||
if a.inExceptOrFinallyStmt > 0:
|
||||
incl s.flags, sfUsedInFinallyOrExcept
|
||||
if isLocalVar(a, s):
|
||||
if sfNoInit in s.flags:
|
||||
# If the variable is explicitly marked as .noinit. do not emit any error
|
||||
@@ -379,6 +381,7 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
|
||||
|
||||
var branches = 1
|
||||
var hasFinally = false
|
||||
inc tracked.inExceptOrFinallyStmt
|
||||
|
||||
# Collect the exceptions caught by the except branches
|
||||
for i in 1..<n.len:
|
||||
@@ -411,6 +414,7 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
|
||||
hasFinally = true
|
||||
|
||||
tracked.bottom = oldBottom
|
||||
dec tracked.inExceptOrFinallyStmt
|
||||
if not hasFinally:
|
||||
setLen(tracked.init, oldState)
|
||||
for id, count in items(inter):
|
||||
|
||||
Reference in New Issue
Block a user