diff options
-rw-r--r-- | compiler/ast.nim | 1 | ||||
-rw-r--r-- | compiler/ccgcalls.nim | 12 | ||||
-rw-r--r-- | compiler/sempass2.nim | 6 |
3 files changed, 15 insertions, 4 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index d13487e9c..76b1d8c91 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -293,6 +293,7 @@ type sfInjectDestructors # whether the proc needs the 'injectdestructors' transformation sfNeverRaises # proc can never raise an exception, not even OverflowDefect # or out-of-memory + sfUsedInFinallyOrExcept # symbol is used inside an 'except' or 'finally' TSymFlags* = set[TSymFlag] diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 10f5ef638..3dd2b54d4 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -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.} = diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 862123eab..6808b1b9b 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -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 @@ -382,6 +384,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: @@ -414,6 +417,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): |