From fe48de44067c2d68d764f7476738d6fd3aee38a7 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:17:52 +0800 Subject: [PATCH] fixes #23837; cursor now processes distinct types with a destructor (#23845) fixes #23837 --- compiler/varpartitions.nim | 13 ++++++++-- tests/destructor/t23837.nim | 51 +++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 tests/destructor/t23837.nim diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 6b2f677a7e..84cf3265c0 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -106,6 +106,7 @@ type unanalysableMutation: bool inAsgnSource, inConstructor, inNoSideEffectSection: int inConditional, inLoop: int + inConvHasDestructor: int owner: PSym g: ModuleGraph @@ -427,9 +428,17 @@ proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) = # primitive literals including the empty are harmless: discard - of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkCast, nkConv: + of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkCast: destMightOwn(c, dest, n[1]) + of nkConv: + if hasDestructor(n.typ): + inc c.inConvHasDestructor + destMightOwn(c, dest, n[1]) + dec c.inConvHasDestructor + else: + destMightOwn(c, dest, n[1]) + of nkIfStmt, nkIfExpr: for i in 0.. 0: # calls do construct, what we construct must be destroyed, # so dest cannot be a cursor: dest.flags.incl ownsData diff --git a/tests/destructor/t23837.nim b/tests/destructor/t23837.nim new file mode 100644 index 0000000000..e219dd6b55 --- /dev/null +++ b/tests/destructor/t23837.nim @@ -0,0 +1,51 @@ +discard """ + output: ''' +Deallocating OwnedString +HelloWorld +''' + matrix: "--cursorinference:on; --cursorinference:off" + target: "c" +""" + +# bug #23837 +{. + emit: [ + """ +#include +#include +char *allocCString() { + char *result = (char *) malloc(10 + 1); + strcpy(result, "HelloWorld"); + return result; +} + +""" + ] +.} + +proc rawWrapper(): cstring {.importc: "allocCString", cdecl.} +proc free(p: pointer) {.importc: "free", cdecl.} + +# ------------------------- + +type OwnedString = distinct cstring + +proc `=destroy`(s: OwnedString) = + free(cstring s) + echo "Deallocating OwnedString" + +func `$`(s: OwnedString): string {.borrow.} + +proc leakyWrapper(): string = + let ostring = rawWrapper().OwnedString + $ostring + +# ------------------------- + +proc main() = + # destructor not called - definitely lost: 11 bytes in 1 blocks + # doesn't leak with --cursorInference:off + let s = leakyWrapper() + echo s + +main() \ No newline at end of file