summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/ccgcalls.nim12
-rw-r--r--compiler/sempass2.nim6
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):