From 935149441c12d748b65b6cbb7ac79d580e8fe02f Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 30 Jan 2024 04:26:41 +0000 Subject: [PATCH] fixes #22672; Destructor not called for result when exception is thrown --- compiler/ccgcalls.nim | 24 +++++++++++++++++++++++- compiler/ccgstmts.nim | 6 ++++++ compiler/cgen.nim | 1 + 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 607f6d51e64b5..27fb28abbb1d2 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -66,6 +66,8 @@ proc preventNrvo(p: BProc; dest, le, ri: PNode): bool = proc hasNoInit(call: PNode): bool {.inline.} = result = call[0].kind == nkSym and sfNoInit in call[0].sym.flags +import renderer + proc isHarmlessStore(p: BProc; canRaise: bool; d: TLoc): bool = if d.k in {locTemp, locNone} or not canRaise: result = true @@ -139,7 +141,27 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, 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 hasDestructor(typ.returnType) and p.nestedTryStmts.len > 0: + var needRaiseExit = true + debug p.nestedTryStmts[^1].fin + var fin = p.nestedTryStmts[^1].fin + if fin.len == 1 and fin[0].kind in {nkStmtList, nkStmtListExpr}: + fin = fin[0] + for dtor in fin: + if dtor.kind == nkCall and dtor[0].kind == nkSym and + dtor[0].sym.name.s == "=destroy" and + sameType(dtor[1].typ, typ.returnType): + var op = initLocExpr(p, dtor[0]) + var callee = rdLoc(op) + let destroy = callee & "(" & rdLoc(tmp) & ")" + raiseExitCleanup(p, destroy) + needRaiseExit = false + break + if needRaiseExit: + raiseExit(p) + else: + raiseExit(p) genAssignment(p, d, tmp, {}) else: pl.add(");\n") diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 28c0851aa6b0e..8c5dfec7e15f2 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -733,6 +733,12 @@ 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: + 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 3a6d9a75abacd..76dac352b9857 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -743,6 +743,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)