more precise analysis about 'observable stores' [backport:1.2] (#14582)
This commit is contained in:
parent
4fdf9cb808
commit
32083c7ff8
3 changed files with 15 additions and 4 deletions
|
|
@ -293,6 +293,7 @@ type
|
||||||
sfInjectDestructors # whether the proc needs the 'injectdestructors' transformation
|
sfInjectDestructors # whether the proc needs the 'injectdestructors' transformation
|
||||||
sfNeverRaises # proc can never raise an exception, not even OverflowDefect
|
sfNeverRaises # proc can never raise an exception, not even OverflowDefect
|
||||||
# or out-of-memory
|
# or out-of-memory
|
||||||
|
sfUsedInFinallyOrExcept # symbol is used inside an 'except' or 'finally'
|
||||||
|
|
||||||
TSymFlags* = set[TSymFlag]
|
TSymFlags* = set[TSymFlag]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,14 +22,20 @@ proc canRaiseDisp(p: BProc; n: PNode): bool =
|
||||||
result = canRaiseConservative(n)
|
result = canRaiseConservative(n)
|
||||||
|
|
||||||
proc preventNrvo(p: BProc; le, ri: PNode): bool =
|
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
|
var n = le
|
||||||
while true:
|
while true:
|
||||||
# do NOT follow nkHiddenDeref here!
|
# do NOT follow nkHiddenDeref here!
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
# we don't own the location so it escapes:
|
# 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,
|
of nkDotExpr, nkBracketExpr, nkObjUpConv, nkObjDownConv,
|
||||||
nkCheckedFieldExpr:
|
nkCheckedFieldExpr:
|
||||||
n = n[0]
|
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
|
# we use the weaker 'canRaise' here in order to prevent too many
|
||||||
# annoying warnings, see #14514
|
# annoying warnings, see #14514
|
||||||
if canRaise(ri[0]) and
|
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)
|
message(p.config, le.info, warnObservableStores, $le)
|
||||||
|
|
||||||
proc hasNoInit(call: PNode): bool {.inline.} =
|
proc hasNoInit(call: PNode): bool {.inline.} =
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ type
|
||||||
TEffects = object
|
TEffects = object
|
||||||
exc: PNode # stack of exceptions
|
exc: PNode # stack of exceptions
|
||||||
tags: PNode # list of tags
|
tags: PNode # list of tags
|
||||||
bottom, inTryStmt: int
|
bottom, inTryStmt, inExceptOrFinallyStmt: int
|
||||||
owner: PSym
|
owner: PSym
|
||||||
ownerModule: PSym
|
ownerModule: PSym
|
||||||
init: seq[int] # list of initialized variables
|
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) =
|
proc useVar(a: PEffects, n: PNode) =
|
||||||
let s = n.sym
|
let s = n.sym
|
||||||
|
if a.inExceptOrFinallyStmt > 0:
|
||||||
|
incl s.flags, sfUsedInFinallyOrExcept
|
||||||
if isLocalVar(a, s):
|
if isLocalVar(a, s):
|
||||||
if sfNoInit in s.flags:
|
if sfNoInit in s.flags:
|
||||||
# If the variable is explicitly marked as .noinit. do not emit any error
|
# If the variable is explicitly marked as .noinit. do not emit any error
|
||||||
|
|
@ -382,6 +384,7 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
|
||||||
|
|
||||||
var branches = 1
|
var branches = 1
|
||||||
var hasFinally = false
|
var hasFinally = false
|
||||||
|
inc tracked.inExceptOrFinallyStmt
|
||||||
|
|
||||||
# Collect the exceptions caught by the except branches
|
# Collect the exceptions caught by the except branches
|
||||||
for i in 1..<n.len:
|
for i in 1..<n.len:
|
||||||
|
|
@ -414,6 +417,7 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
|
||||||
hasFinally = true
|
hasFinally = true
|
||||||
|
|
||||||
tracked.bottom = oldBottom
|
tracked.bottom = oldBottom
|
||||||
|
dec tracked.inExceptOrFinallyStmt
|
||||||
if not hasFinally:
|
if not hasFinally:
|
||||||
setLen(tracked.init, oldState)
|
setLen(tracked.init, oldState)
|
||||||
for id, count in items(inter):
|
for id, count in items(inter):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue