summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ccgcalls.nim30
-rw-r--r--compiler/ccgstmts.nim12
-rw-r--r--compiler/cgen.nim1
-rw-r--r--tests/errmsgs/t22852.nim9
-rw-r--r--tests/stdlib/tjson.nim4
5 files changed, 51 insertions, 5 deletions
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 6b716f759..81c0fb555 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -76,6 +76,23 @@ proc isHarmlessStore(p: BProc; canRaise: bool; d: TLoc): bool =
   else:
     result = false
 
+proc cleanupTemp(p: BProc; returnType: PType, tmp: TLoc): bool =
+  if returnType.kind in {tyVar, tyLent}:
+    # we don't need to worry about var/lent return types
+    result = false
+  elif hasDestructor(returnType) and getAttachedOp(p.module.g.graph, returnType, attachedDestructor) != nil:
+    let dtor = getAttachedOp(p.module.g.graph, returnType, attachedDestructor)
+    var op = initLocExpr(p, newSymNode(dtor))
+    var callee = rdLoc(op)
+    let destroy = if dtor.typ.firstParamType.kind == tyVar:
+        callee & "(&" & rdLoc(tmp) & ")"
+      else:
+        callee & "(" & rdLoc(tmp) & ")"
+    raiseExitCleanup(p, destroy)
+    result = true
+  else:
+    result = false
+
 proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
                callee, params: Rope) =
   let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
@@ -128,18 +145,25 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
             if canRaise: raiseExit(p)
 
       elif isHarmlessStore(p, canRaise, d):
-        if d.k == locNone: d = getTemp(p, typ.returnType)
+        var useTemp = false
+        if d.k == locNone:
+          useTemp = true
+          d = getTemp(p, typ.returnType)
         assert(d.t != nil)        # generate an assignment to d:
         var list = initLoc(locCall, d.lode, OnUnknown)
         list.r = pl
         genAssignment(p, d, list, flags) # no need for deep copying
-        if canRaise: raiseExit(p)
+        if canRaise:
+          if not (useTemp and cleanupTemp(p, typ.returnType, d)):
+            raiseExit(p)
       else:
         var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
         var list = initLoc(locCall, d.lode, OnUnknown)
         list.r = pl
         genAssignment(p, tmp, list, flags) # no need for deep copying
-        if canRaise: raiseExit(p)
+        if canRaise:
+          if not cleanupTemp(p, typ.returnType, tmp):
+            raiseExit(p)
         genAssignment(p, d, tmp, {})
   else:
     pl.add(");\n")
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index a55512466..4f79068c5 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -755,6 +755,18 @@ proc raiseExit(p: BProc) =
       lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto LA$1_;$n",
         [p.nestedTryStmts[^1].label])
 
+proc raiseExitCleanup(p: BProc, destroy: string) =
+  assert p.config.exc == excGoto
+  if nimErrorFlagDisabled notin p.flags:
+    p.flags.incl nimErrorFlagAccessed
+    if p.nestedTryStmts.len == 0:
+      p.flags.incl beforeRetNeeded
+      # easy case, simply goto 'ret':
+      lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) {$1; goto BeforeRet_;}$n", [destroy])
+    else:
+      lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) {$2; goto LA$1_;}$n",
+        [p.nestedTryStmts[^1].label, destroy])
+
 proc finallyActions(p: BProc) =
   if p.config.exc != excGoto and p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept:
     # if the current try stmt have a finally block,
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index c69e12a20..437928039 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -752,6 +752,7 @@ proc intLiteral(i: BiggestInt; result: var Rope)
 proc genLiteral(p: BProc, n: PNode; result: var Rope)
 proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; argsCounter: var int)
 proc raiseExit(p: BProc)
+proc raiseExitCleanup(p: BProc, destroy: string)
 
 proc initLocExpr(p: BProc, e: PNode, flags: TLocFlags = {}): TLoc =
   result = initLoc(locNone, e, OnUnknown, flags)
diff --git a/tests/errmsgs/t22852.nim b/tests/errmsgs/t22852.nim
new file mode 100644
index 000000000..7c352a49c
--- /dev/null
+++ b/tests/errmsgs/t22852.nim
@@ -0,0 +1,9 @@
+discard """
+  exitcode: 1
+  outputsub: '''
+Error: unhandled exception: value out of range: -2 notin 0 .. 9223372036854775807 [RangeDefect]
+'''
+"""
+
+# bug #22852
+echo [0][2..^2]
diff --git a/tests/stdlib/tjson.nim b/tests/stdlib/tjson.nim
index 691bedeaa..f0e8c8bb7 100644
--- a/tests/stdlib/tjson.nim
+++ b/tests/stdlib/tjson.nim
@@ -1,5 +1,5 @@
 discard """
-  matrix: "--mm:refc; --backend:cpp --mm:refc; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on"
+  matrix: "; --backend:cpp; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on"
 """
 
 
@@ -51,7 +51,7 @@ for i in 0 .. 10000:
   except:
     discard
 # memory diff should less than 4M
-doAssert(abs(getOccupiedMem() - startMemory) < 4 * 1024 * 1024) # todo fixme doesn;t work for ORC
+doAssert(abs(getOccupiedMem() - startMemory) < 4 * 1024 * 1024)
 
 
 # test `$`