diff options
author | ringabout <43030857+ringabout@users.noreply.github.com> | 2024-06-06 17:51:41 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-06 11:51:41 +0200 |
commit | 8f5ae28fab113c425d22e5abc230f456fa627744 (patch) | |
tree | f3a82b83cc0460d500b73530a4707dddfa5ded24 | |
parent | 69d0b73d667c4be9383f29cda3f70e411995d9af (diff) | |
download | Nim-8f5ae28fab113c425d22e5abc230f456fa627744.tar.gz |
fixes #22672; Destructor not called for result when exception is thrown (#23267)
fixes #22672
-rw-r--r-- | compiler/ccgcalls.nim | 30 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 12 | ||||
-rw-r--r-- | compiler/cgen.nim | 1 | ||||
-rw-r--r-- | tests/errmsgs/t22852.nim | 9 | ||||
-rw-r--r-- | tests/stdlib/tjson.nim | 4 |
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 `$` |