more precise analysis about 'observable stores' [backport:1.2] (#14582)

This commit is contained in:
Andreas Rumpf 2020-06-06 21:28:46 +02:00 • committed by GitHub
commit 32083c7ff8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 15 additions and 4 deletions

View file

@ -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]

View file

@ -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.} =

View file

@ -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):