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

(cherry picked from commit 32083c7ff8)
This commit is contained in:
Andreas Rumpf
2020-06-06 21:28:46 +02:00
committed by narimiran
parent 33bf7839ba
commit 10fb986fb6
3 changed files with 15 additions and 4 deletions

View File

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

View File

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

View File

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