diff options
Diffstat (limited to 'tests/destructor')
49 files changed, 1005 insertions, 132 deletions
diff --git a/tests/destructor/const_smart_ptr.nim b/tests/destructor/const_smart_ptr.nim index 4d8c7c9a3..25dd46500 100644 --- a/tests/destructor/const_smart_ptr.nim +++ b/tests/destructor/const_smart_ptr.nim @@ -2,13 +2,12 @@ type ConstPtr*[T] = object val: ptr T -proc `=destroy`*[T](p: var ConstPtr[T]) = +proc `=destroy`*[T](p: ConstPtr[T]) = if p.val != nil: `=destroy`(p.val[]) dealloc(p.val) - p.val = nil -proc `=`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.error.} +proc `=copy`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.error.} proc `=sink`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.inline.} = if dest.val != nil and dest.val != src.val: @@ -31,12 +30,11 @@ type len: int data: ptr UncheckedArray[float] -proc `=destroy`*(m: var MySeqNonCopyable) {.inline.} = +proc `=destroy`*(m: MySeqNonCopyable) {.inline.} = if m.data != nil: deallocShared(m.data) - m.data = nil -proc `=`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.error.} +proc `=copy`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.error.} proc `=sink`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.inline.} = if m.data != m2.data: diff --git a/tests/destructor/nim.cfg b/tests/destructor/nim.cfg new file mode 100644 index 000000000..7c148b797 --- /dev/null +++ b/tests/destructor/nim.cfg @@ -0,0 +1 @@ +--sinkInference:on diff --git a/tests/destructor/t12037.nim b/tests/destructor/t12037.nim index 1a7d536cc..30266690f 100644 --- a/tests/destructor/t12037.nim +++ b/tests/destructor/t12037.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c --newruntime $file''' + cmd: '''nim c --gc:arc $file''' output: ''' showing original type, length, and contents seq[int] 1 @[42] copy length and contents 1 @[42] @@ -9,11 +9,11 @@ copy length and contents 1 @[42] proc test() = var sq1 = @[42] echo "showing original type, length, and contents ", sq1.typeof, " ", sq1.len, " ", sq1 - doAssert cast[int](sq1[0].unsafeAddr) != 0 + doAssert cast[int](sq1[0].addr) != 0 var sq2 = sq1 # copy of original echo "copy length and contents ", sq2.len, " ", sq2 - doAssert cast[int](sq2[0].unsafeAddr) != 0 - doAssert cast[int](sq1[0].unsafeAddr) != 0 + doAssert cast[int](sq2[0].addr) != 0 + doAssert cast[int](sq1[0].addr) != 0 test() diff --git a/tests/destructor/t16607.nim b/tests/destructor/t16607.nim new file mode 100644 index 000000000..f98a6d517 --- /dev/null +++ b/tests/destructor/t16607.nim @@ -0,0 +1,23 @@ +discard """ + matrix: "--gc:refc; --gc:arc" +""" + +# bug #16607 + +type + O {.requiresInit.} = object + initialized: bool + +proc `=destroy`(o: var O) = + doAssert o.initialized, "O was destroyed before initialization!" + +proc initO(): O = + O(initialized: true) + +proc pair(): tuple[a, b: O] = + result = (a: initO(), b: initO()) + +proc main() = + discard pair() + +main() diff --git a/tests/destructor/t17198.nim b/tests/destructor/t17198.nim new file mode 100644 index 000000000..098db8245 --- /dev/null +++ b/tests/destructor/t17198.nim @@ -0,0 +1,32 @@ +discard """ + cmd: '''nim c --gc:arc $file''' + output: ''' +other +''' +""" + +import std/macros + +macro bigCaseStmt(arg: untyped): untyped = + result = nnkCaseStmt.newTree(arg) + + # try to change 2000 to a bigger value if it doesn't crash + for x in 0 ..< 2000: + result.add nnkOfBranch.newTree(newStrLitNode($x), newStrLitNode($x)) + + result.add nnkElse.newTree(newStrLitNode("other")) + +macro bigIfElseExpr(): untyped = + result = nnkIfExpr.newTree() + + for x in 0 ..< 1000: + result.add nnkElifExpr.newTree(newLit(false), newStrLitNode($x)) + + result.add nnkElseExpr.newTree(newStrLitNode("other")) + +proc test(arg: string): string = + echo bigIfElseExpr() + + result = bigCaseStmt(arg) + +discard test("test") diff --git a/tests/destructor/t23748.nim b/tests/destructor/t23748.nim new file mode 100644 index 000000000..a3738733e --- /dev/null +++ b/tests/destructor/t23748.nim @@ -0,0 +1,31 @@ +discard """ + matrix: "--gc:refc; --gc:arc" + output: ''' +hello 42 +hello 42 +len = 2 +''' +""" + +# bug #23748 + +type + O = ref object + s: string + cb: seq[proc()] + +proc push1(o: O, i: int) = + let o = o + echo o.s, " ", i + o.cb.add(proc() = echo o.s, " ", i) + +proc push2(o: O, i: int) = + let o = o + echo o.s, " ", i + proc p() = echo o.s, " ", i + o.cb.add(p) + +let o = O(s: "hello", cb: @[]) +o.push1(42) +o.push2(42) +echo "len = ", o.cb.len diff --git a/tests/destructor/t23837.nim b/tests/destructor/t23837.nim new file mode 100644 index 000000000..e219dd6b5 --- /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 <stdlib.h> +#include <string.h> +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 diff --git a/tests/destructor/t5342.nim b/tests/destructor/t5342.nim new file mode 100644 index 000000000..0acd5ef9d --- /dev/null +++ b/tests/destructor/t5342.nim @@ -0,0 +1,24 @@ +discard """ + matrix: "--mm:refc; --mm:arc" + targets: "c js" + output: ''' +1 +2 +here +2 +1 +''' +""" + + +type + A = object + id: int + B = object + a: A +proc `=destroy`(a: var A) = echo a.id +var x = A(id: 1) +var y = B(a: A(id: 2)) +`=destroy`(x) +`=destroy`(y) +echo "here" \ No newline at end of file diff --git a/tests/destructor/t7346.nim b/tests/destructor/t7346.nim index 9e5292a61..3834d39ff 100644 --- a/tests/destructor/t7346.nim +++ b/tests/destructor/t7346.nim @@ -2,8 +2,7 @@ discard """ joinable: false """ -when not defined(nimNewRuntime): - {.error: "This bug could only be reproduced with --newruntime".} +# This bug could only be reproduced with --newruntime type Obj = object diff --git a/tests/destructor/t9440.nim b/tests/destructor/t9440.nim new file mode 100644 index 000000000..153bb303d --- /dev/null +++ b/tests/destructor/t9440.nim @@ -0,0 +1,52 @@ +discard """ + matrix: "--gc:refc; --gc:orc; --gc:arc" + output: ''' +() +Destroyed +() +Destroyed +() +Destroyed +end +------------------------- +() +Destroyed +end +''' + +""" + +# bug #9440 +block: + type + X = object + + proc `=destroy`(x: var X) = + echo "Destroyed" + + proc main() = + for x in 0 .. 2: + var obj = X() + echo obj + # The destructor call is invoked after "end" is printed + echo "end" + + main() + +echo "-------------------------" + +block: + type + X = object + + proc `=destroy`(x: var X) = + echo "Destroyed" + + proc main() = + block: + var obj = X() + echo obj + # The destructor is not called when obj goes out of scope + echo "end" + + main() diff --git a/tests/destructor/tarc.nim b/tests/destructor/tarc.nim index 12ea46b2c..54d75a410 100644 --- a/tests/destructor/tarc.nim +++ b/tests/destructor/tarc.nim @@ -8,6 +8,8 @@ Hello 2 0 List +@["4", "5", "6", "", "", "a", ""] +@["", "", "a", ""] ''' cmd: '''nim c --gc:arc $file''' """ @@ -162,10 +164,21 @@ type case kind: TagKind of List: values: seq[Tag] - of Compound: + of Compound: compound: Table[string, Tag] var a = Tag(kind: List) var b = a echo a.kind var c = a + +proc testAdd(i: int; yyy: openArray[string]) = + var x: seq[string] + x.add [$i, $(i+1), $(i+2)] + x.add yyy + echo x + +var y = newSeq[string](4) +y[2] = "a" +testAdd(4, y) +echo y diff --git a/tests/destructor/tarray_indexing.nim b/tests/destructor/tarray_indexing.nim index 7efd5a00c..a9dfdf4ed 100644 --- a/tests/destructor/tarray_indexing.nim +++ b/tests/destructor/tarray_indexing.nim @@ -1,7 +1,7 @@ discard """ output: '''allocating 1048576 65536 filling page from 1048576 len 65536''' - cmd: '''nim c --newruntime $file''' + cmd: '''nim c --gc:arc $file''' """ # bug #12669 @@ -63,7 +63,7 @@ proc fillPages*(mem: UserProcessMemory, start: uint32, data: seq[byte]) = #echo cast[uint64](addr mem.pageAccess[i]) let page = mem.pageAccess[i] assert page != nil - #copyMem(page, unsafeAddr data[i * 0x1000 - start], 0x1000) + #copyMem(page, addr data[i * 0x1000 - start], 0x1000) const base = 0x00100000 diff --git a/tests/destructor/tatomicptrs.nim b/tests/destructor/tatomicptrs.nim index 7313afbf5..82870ac82 100644 --- a/tests/destructor/tatomicptrs.nim +++ b/tests/destructor/tatomicptrs.nim @@ -27,7 +27,7 @@ template decRef(x): untyped = atomicDec(x.refcount) proc makeShared*[T](x: sink T): SharedPtr[T] = # XXX could benefit from a macro that generates it. - result = cast[SharedPtr[T]](allocShared(sizeof(x))) + result = cast[SharedPtr[T]](allocShared0(sizeof(x))) result.x[] = x echo "allocating" @@ -39,7 +39,7 @@ proc `=destroy`*[T](dest: var SharedPtr[T]) = echo "deallocating" dest.x = nil -proc `=`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) = +proc `=copy`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) = var s = src.x if s != nil: incRef(s) #atomicSwap(dest, s) @@ -50,6 +50,9 @@ proc `=`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) = deallocShared(s) echo "deallocating" +proc `=dup`*[T](src: SharedPtr[T]): SharedPtr[T] = + `=copy`(result, src) + proc `=sink`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) = ## XXX make this an atomic store: if dest.x != src.x: @@ -72,6 +75,7 @@ template `.=`*[T](s: SharedPtr[T]; field, value: untyped) = from macros import unpackVarargs template `.()`*[T](s: SharedPtr[T]; field: untyped, args: varargs[untyped]): untyped = + # xxx this isn't used, the test should be improved unpackVarargs(s.x.field, args) @@ -119,7 +123,7 @@ proc `=destroy`*[T](m: var MySeq[T]) {.inline.} = deallocShared(m.data) m.data = nil -proc `=`*[T](m: var MySeq[T], m2: MySeq[T]) = +proc `=copy`*[T](m: var MySeq[T], m2: MySeq[T]) = if m.data == m2.data: return if m.data != nil: `=destroy`(m) @@ -130,17 +134,22 @@ proc `=`*[T](m: var MySeq[T], m2: MySeq[T]) = m.data = cast[ptr UncheckedArray[T]](allocShared(bytes)) copyMem(m.data, m2.data, bytes) +proc `=dup`*[T](m: MySeq[T]): MySeq[T] = + `=copy`[T](result, m) + proc `=sink`*[T](m: var MySeq[T], m2: MySeq[T]) {.inline.} = if m.data != m2.data: if m.data != nil: `=destroy`(m) m.len = m2.len m.data = m2.data + m.refcount = m2.refcount proc len*[T](m: MySeq[T]): int {.inline.} = m.len proc newMySeq*[T](size: int, initial_value: T): MySeq[T] = result.len = size + result.refcount = 1 if size > 0: result.data = cast[ptr UncheckedArray[T]](allocShared(sizeof(T) * size)) diff --git a/tests/destructor/tbintree2.nim b/tests/destructor/tbintree2.nim index 6fdda6e54..d56c2850b 100644 --- a/tests/destructor/tbintree2.nim +++ b/tests/destructor/tbintree2.nim @@ -21,21 +21,21 @@ proc merge(lower, greater: owned Node): owned Node = elif greater.isNil: result = lower elif lower.y < greater.y: - lower.right = merge(lower.right, greater) + lower.right = merge(move lower.right, greater) result = lower else: - greater.left = merge(lower, greater.left) + greater.left = merge(lower, move greater.left) result = greater proc splitBinary(orig: owned Node, value: int32): (owned Node, owned Node) = if orig.isNil: result = (nil, nil) elif orig.x < value: - let splitPair = splitBinary(orig.right, value) + let splitPair = splitBinary(move orig.right, value) orig.right = splitPair[0] result = (orig, splitPair[1]) else: - let splitPair = splitBinary(orig.left, value) + let splitPair = splitBinary(move orig.left, value) orig.left = splitPair[1] result = (splitPair[0], orig) @@ -57,7 +57,7 @@ proc `=destroy`(t: var Tree) {.nodestroy.} = let x = s.pop if x.left != nil: s.add(x.left) if x.right != nil: s.add(x.right) - dispose(x) + `=dispose`(x) `=destroy`(s) proc hasValue(self: var Tree, x: int32): bool = diff --git a/tests/destructor/tcaseobj_transitions.nim b/tests/destructor/tcaseobj_transitions.nim index 4e203f4ef..61464101f 100644 --- a/tests/destructor/tcaseobj_transitions.nim +++ b/tests/destructor/tcaseobj_transitions.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c --newruntime $file''' + cmd: '''nim c --gc:arc $file''' output: '''no crash''' """ diff --git a/tests/destructor/tcomplexobjconstr.nim b/tests/destructor/tcomplexobjconstr.nim index fd112b6e2..aea0ad1fe 100644 --- a/tests/destructor/tcomplexobjconstr.nim +++ b/tests/destructor/tcomplexobjconstr.nim @@ -20,16 +20,16 @@ type of true: y*: float var x = new(MyObject2) -assert x of MyObject2 -assert x.subobj of MyObject1 -assert x.more[2] of MyObject1 -assert x.more[2] of RootObj +doAssert x of MyObject2 +doAssert x.subobj of MyObject1 +doAssert x.more[2] of MyObject1 +doAssert x.more[2] of RootObj var y: MyObject2 -assert y of MyObject2 -assert y.subobj of MyObject1 -assert y.more[2] of MyObject1 -assert y.more[2] of RootObj +doAssert y of MyObject2 +doAssert y.subobj of MyObject1 +doAssert y.more[2] of MyObject1 +doAssert y.more[2] of RootObj echo "true" diff --git a/tests/destructor/tconsume_twice.nim b/tests/destructor/tconsume_twice.nim index 0030267f8..b0a039e9b 100644 --- a/tests/destructor/tconsume_twice.nim +++ b/tests/destructor/tconsume_twice.nim @@ -1,6 +1,6 @@ discard """ cmd: "nim c --newruntime $file" - errormsg: "'=' is not available for type <owned Foo>; requires a copy because it's not the last read of 'a'; another read is done here: tconsume_twice.nim(13, 10); routine: consumeTwice" + errormsg: "'=copy' is not available for type <owned Foo>; requires a copy because it's not the last read of 'a'; another read is done here: tconsume_twice.nim(13, 10); routine: consumeTwice" line: 11 """ type diff --git a/tests/destructor/tcustomseqs.nim b/tests/destructor/tcustomseqs.nim index 4087dc4a8..17a19f871 100644 --- a/tests/destructor/tcustomseqs.nim +++ b/tests/destructor/tcustomseqs.nim @@ -121,7 +121,7 @@ proc createSeq*[T](elems: varargs[T]): myseq[T] = result.data = cast[type(result.data)](alloc(result.cap * sizeof(T))) inc allocCount when supportsCopyMem(T): - copyMem(result.data, unsafeAddr(elems[0]), result.cap * sizeof(T)) + copyMem(result.data, addr(elems[0]), result.cap * sizeof(T)) else: for i in 0..<result.len: result.data[i] = elems[i] diff --git a/tests/destructor/tcustomstrings.nim b/tests/destructor/tcustomstrings.nim index 9ee2da33a..31891856b 100644 --- a/tests/destructor/tcustomstrings.nim +++ b/tests/destructor/tcustomstrings.nim @@ -8,8 +8,6 @@ after 20 20''' joinable: false """ -{.this: self.} - type mystring = object len, cap: int @@ -51,7 +49,7 @@ proc resize(self: var mystring) = if self.cap == 0: self.cap = 8 else: self.cap = (self.cap * 3) shr 1 if self.data == nil: inc allocCount - self.data = cast[type(data)](realloc(self.data, self.cap + 1)) + self.data = cast[type(self.data)](realloc(self.data, self.cap + 1)) proc add*(self: var mystring; c: char) = if self.len >= self.cap: resize(self) @@ -60,22 +58,22 @@ proc add*(self: var mystring; c: char) = inc self.len proc ensure(self: var mystring; newLen: int) = - if newLen >= cap: - cap = max((cap * 3) shr 1, newLen) - if cap > 0: - if data == nil: inc allocCount - data = cast[type(data)](realloc(data, cap + 1)) + if newLen >= self.cap: + self.cap = max((self.cap * 3) shr 1, newLen) + if self.cap > 0: + if self.data == nil: inc allocCount + self.data = cast[type(self.data)](realloc(self.data, self.cap + 1)) proc add*(self: var mystring; y: mystring) = - let newLen = len + y.len + let newLen = self.len + y.len ensure(self, newLen) - copyMem(addr data[len], y.data, y.data.len + 1) - len = newLen + copyMem(addr self.data[self.len], y.data, y.data.len + 1) + self.len = newLen proc create*(lit: string): mystring = let newLen = lit.len ensure(result, newLen) - copyMem(addr result.data[result.len], unsafeAddr lit[0], newLen + 1) + copyMem(addr result.data[result.len], addr lit[0], newLen + 1) result.len = newLen proc `&`*(a, b: mystring): mystring = diff --git a/tests/destructor/tdestructor3.nim b/tests/destructor/tdestructor3.nim index b68aedce9..3f5eb2cc1 100644 --- a/tests/destructor/tdestructor3.nim +++ b/tests/destructor/tdestructor3.nim @@ -1,5 +1,6 @@ discard """ - output: '''assign + output: ''' +assign destroy destroy 5 @@ -22,17 +23,18 @@ joinable: false type T = object proc `=`(lhs: var T, rhs: T) = - echo "assign" + echo "assign" proc `=destroy`(v: var T) = - echo "destroy" + echo "destroy" proc use(x: T) = discard proc usedToBeBlock = - var v1 : T - var v2 : T = v1 - use v1 + var v1 = T() + var v2: T = v1 + discard addr(v2) # prevent cursorfication + use v1 usedToBeBlock() @@ -104,12 +106,12 @@ test() #------------------------------------------------------------ # Issue #12883 -type +type TopObject = object internal: UniquePtr[int] proc deleteTop(p: ptr TopObject) = - if p != nil: + if p != nil: `=destroy`(p[]) # !!! this operation used to leak the integer deallocshared(p) @@ -117,12 +119,67 @@ proc createTop(): ptr TopObject = result = cast[ptr TopObject](allocShared0(sizeof(TopObject))) result.internal = newUniquePtr(1) -proc test2() = +proc test2() = let x = createTop() echo $x.internal deleteTop(x) -echo "---------------" +echo "---------------" echo "app begin" test2() -echo "app end" \ No newline at end of file +echo "app end" + +# bug #14601 + +when true: # D20200607T202043 + type Foo2 = object + x: int + x2: array[10, int] + + type Vec = object + vals: seq[Foo2] + + proc `=destroy`*(a: var Foo2) {.inline.} = + discard + + proc initFoo2(x: int): Foo2 = Foo2(x: x) + + proc add2(v: var Vec, a: Foo2) = # ditto with `a: sink Foo2` + v.vals.add a + + proc add3(v: var Vec, a: Foo2) = # ditto with `a: sink Foo2` + v.vals = @[a] + + proc add4(v: var Vec, a: sink Foo2) = # ditto with `a: sink Foo2` + v.vals.add a + + proc add5(v: var Vec, a: sink Foo2) = # ditto with `a: sink Foo2` + v.vals = @[a] + + proc main2()= + var a: Vec + var b = Foo2(x: 10) + a.add2 b # ok + a.vals.add Foo2(x: 10) # ok + a.add2 initFoo2(x = 10) # ok + a.add2 Foo2(x: 10) # bug + a.add3 initFoo2(x = 10) # ok + a.add3 Foo2(x: 10) # bug + a.add4 initFoo2(x = 10) # ok + a.add4 Foo2(x: 10) # bug + a.add5 initFoo2(x = 10) # ok + a.add5 Foo2(x: 10) # bug + main2() + + + +#------------------------------------------------------------ +# Issue #15825 + +type + Union = string | int | char + +proc run(a: sink Union) = + discard + +run("123") diff --git a/tests/destructor/tdestructor_too_late.nim b/tests/destructor/tdestructor_too_late.nim index d279280ba..76d1dde84 100644 --- a/tests/destructor/tdestructor_too_late.nim +++ b/tests/destructor/tdestructor_too_late.nim @@ -1,5 +1,5 @@ discard """ - errmsg: "cannot bind another '=destroy' to: Obj; previous declaration was constructed here implicitly: tdestructor_too_late.nim(7, 16)" + errormsg: "cannot bind another '=destroy' to: Obj; previous declaration was constructed here implicitly: tdestructor_too_late.nim(7, 16)" """ type Obj* = object v*: int diff --git a/tests/destructor/tdistinctseq.nim b/tests/destructor/tdistinctseq.nim new file mode 100644 index 000000000..5a2ac5ead --- /dev/null +++ b/tests/destructor/tdistinctseq.nim @@ -0,0 +1,8 @@ +discard """ + matrix: "-u:nimPreviewNonVarDestructor;" +""" +type DistinctSeq* = distinct seq[int] + +# `=destroy`(cast[ptr DistinctSeq](0)[]) +var x = @[].DistinctSeq +`=destroy`(x) diff --git a/tests/destructor/tdont_return_unowned_from_owned.nim b/tests/destructor/tdont_return_unowned_from_owned.nim index a726960c6..ffe87cd76 100644 --- a/tests/destructor/tdont_return_unowned_from_owned.nim +++ b/tests/destructor/tdont_return_unowned_from_owned.nim @@ -1,8 +1,12 @@ discard """ cmd: "nim check --newruntime --hints:off $file" - nimout: '''tdont_return_unowned_from_owned.nim(36, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type -tdont_return_unowned_from_owned.nim(39, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type -tdont_return_unowned_from_owned.nim(42, 6) Error: type mismatch: got <Obj> + nimout: ''' +tdont_return_unowned_from_owned.nim(26, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref +tdont_return_unowned_from_owned.nim(27, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref +tdont_return_unowned_from_owned.nim(31, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type +tdont_return_unowned_from_owned.nim(43, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type +tdont_return_unowned_from_owned.nim(46, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type +tdont_return_unowned_from_owned.nim(49, 6) Error: type mismatch: got <Obj> but expected one of: proc new[T](a: var ref T; finalizer: proc (x: ref T) {.nimcall.}) first type mismatch at position: 2 @@ -10,18 +14,21 @@ proc new[T](a: var ref T; finalizer: proc (x: ref T) {.nimcall.}) 2 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them expression: new(result) -tdont_return_unowned_from_owned.nim(42, 6) Error: illformed AST: -tdont_return_unowned_from_owned.nim(50, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref -tdont_return_unowned_from_owned.nim(51, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref -tdont_return_unowned_from_owned.nim(55, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type +tdont_return_unowned_from_owned.nim(49, 6) Error: illformed AST: ''' - errormsg: "cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type" - line: 55 + errormsg: "illformed AST:" """ +proc testA(result: var (RootRef, RootRef)) = + let r: owned RootRef = RootRef() + result[0] = r + result[1] = RootRef() +proc testB(): RootRef = + let r: owned RootRef = RootRef() + result = r @@ -39,17 +46,11 @@ proc newObjB(): Obj = result = Obj() proc newObjC(): Obj = - new(result) + new(result) # illFormedAst raises GlobalError, + # without pipeline parsing, it needs to placed at the end + # in case that it disturbs other errors let a = newObjA() let b = newObjB() let c = newObjC() -proc testA(result: var (RootRef, RootRef)) = - let r: owned RootRef = RootRef() - result[0] = r - result[1] = RootRef() - -proc testB(): RootRef = - let r: owned RootRef = RootRef() - result = r diff --git a/tests/destructor/tgcdestructors.nim b/tests/destructor/tgcdestructors.nim index 4731bf694..07a3731a0 100644 --- a/tests/destructor/tgcdestructors.nim +++ b/tests/destructor/tgcdestructors.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c -d:nimAllocStats --newruntime $file''' + cmd: '''nim c -d:nimAllocStats --gc:arc $file''' output: '''hi ho ha diff --git a/tests/destructor/tglobaldestructor.nim b/tests/destructor/tglobaldestructor.nim index 403f670a0..4d002a092 100644 --- a/tests/destructor/tglobaldestructor.nim +++ b/tests/destructor/tglobaldestructor.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c --newruntime $file''' + cmd: '''nim c --gc:arc $file''' output: '''(v: 42) igotdestroyed''' """ diff --git a/tests/destructor/tgotoexc_leak.nim b/tests/destructor/tgotoexc_leak.nim new file mode 100644 index 000000000..c8a234085 --- /dev/null +++ b/tests/destructor/tgotoexc_leak.nim @@ -0,0 +1,19 @@ +discard """ + output: '''0 +true''' + cmd: "nim c --gc:arc $file" +""" + +# bug #22398 + +for i in 0 ..< 10_000: + try: + try: + raise newException(ValueError, "") + except CatchableError: + discard + raise newException(ValueError, "") # or raise getCurrentException(), just raise works ok + except ValueError: + discard +echo getOccupiedMem() +echo getCurrentException() == nil diff --git a/tests/destructor/tgotoexceptions7.nim b/tests/destructor/tgotoexceptions7.nim index 6e564a044..c04bd6ba0 100644 --- a/tests/destructor/tgotoexceptions7.nim +++ b/tests/destructor/tgotoexceptions7.nim @@ -25,7 +25,8 @@ proc helper = doAssert(false) proc main(i: int) = var obj = Obj(kind: kindA, s: "abc") - obj.kind = kindB + {.cast(uncheckedAssign).}: + obj.kind = kindB obj.i = 2 try: var objA = ObjA() diff --git a/tests/destructor/tgotoexceptions8.nim b/tests/destructor/tgotoexceptions8.nim index e968cdce2..8ed2ed0ba 100644 --- a/tests/destructor/tgotoexceptions8.nim +++ b/tests/destructor/tgotoexceptions8.nim @@ -8,7 +8,8 @@ outer finally msg1 msg2 finally2 -finally1''' +finally1 +true''' cmd: "nim c --gc:arc $file" """ @@ -67,3 +68,9 @@ when true: echo "finally1" nested_finally() + +# bug #14925 +proc test(b: bool) = + echo b + +test(try: true except: false) diff --git a/tests/destructor/tmatrix.nim b/tests/destructor/tmatrix.nim index a3bd59df3..2fd5af789 100644 --- a/tests/destructor/tmatrix.nim +++ b/tests/destructor/tmatrix.nim @@ -31,7 +31,7 @@ proc `=sink`*(a: var Matrix; b: Matrix) = a.m = b.m a.n = b.n -proc `=`*(a: var Matrix; b: Matrix) = +proc `=copy`*(a: var Matrix; b: Matrix) = if a.data != nil and a.data != b.data: dealloc(a.data) deallocCount.inc @@ -43,6 +43,9 @@ proc `=`*(a: var Matrix; b: Matrix) = allocCount.inc copyMem(a.data, b.data, b.m * b.n * sizeof(float)) +proc `=dup`*(a: Matrix): Matrix = + `=copy`(result, a) + proc matrix*(m, n: int, s: float): Matrix = ## Construct an m-by-n constant matrix. result.m = m @@ -96,14 +99,16 @@ proc info = allocCount = 0 deallocCount = 0 +proc copy(a: Matrix): Matrix = a + proc test1 = var a = matrix(5, 5, 1.0) - var b = a + var b = copy a var c = a + b proc test2 = var a = matrix(5, 5, 1.0) - var b = a + var b = copy a var c = -a proc test3 = diff --git a/tests/destructor/tmisc_destructors.nim b/tests/destructor/tmisc_destructors.nim index 73c54eab3..082cb0f78 100644 --- a/tests/destructor/tmisc_destructors.nim +++ b/tests/destructor/tmisc_destructors.nim @@ -21,11 +21,13 @@ proc `=sink`(dest: var Foo, src: Foo) = proc `=`(dest: var Foo, src: Foo) = assign_counter.inc +proc createFoo(): Foo = Foo(boo: 0) + proc test(): auto = - var a, b: Foo + var a, b = createFoo() return (a, b, Foo(boo: 5)) -var (a, b, _) = test() +var (ag, bg, _) = test() doAssert assign_counter == 0 doAssert sink_counter == 0 diff --git a/tests/destructor/tmove.nim b/tests/destructor/tmove.nim new file mode 100644 index 000000000..2762aff90 --- /dev/null +++ b/tests/destructor/tmove.nim @@ -0,0 +1,18 @@ +discard """ + targets: "c cpp" +""" + +block: + var called = 0 + + proc bar(a: var int): var int = + inc called + result = a + + proc foo = + var a = 2 + var s = move bar(a) + doAssert called == 1 + doAssert s == 2 + + foo() diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim index 5366f4957..cdc1eb1c0 100644 --- a/tests/destructor/tmove_objconstr.nim +++ b/tests/destructor/tmove_objconstr.nim @@ -2,14 +2,13 @@ discard """ output: '''test created test destroyed 0 -Pony is dying! 1 2 3 4 Pony is dying!''' joinable: false -target: "C" +targets: "c" """ # bug #4214 @@ -51,7 +50,7 @@ proc `=destroy`(o: var Pony) = echo "Pony is dying!" proc getPony: Pony = - result.name = "Sparkles" + result = Pony(name: "Sparkles") iterator items(p: Pony): int = for i in 1..4: @@ -113,7 +112,7 @@ proc myfunc2(x, y: int): tuple[a: MySeqNonCopyable, b:int, c:MySeqNonCopyable] = var cc = newMySeq(y, 5.0) (a: case x: of 1: - let (z1, z2) = myfunc(x,y) + let (z1, z2) = myfunc(x, y) z2 elif x > 5: raise newException(ValueError, "new error") else: newMySeq(x, 1.0), @@ -138,28 +137,29 @@ doAssert seq3[0] == 1.0 var seq4, seq5: MySeqNonCopyable (seq4, i, seq5) = myfunc2(2, 3) -seq4 = block: - var tmp = newMySeq(4, 1.0) - tmp[0] = 3.0 - tmp +proc foo = + seq4 = block: + var tmp = newMySeq(4, 1.0) + tmp[0] = 3.0 + tmp -doAssert seq4[0] == 3.0 + doAssert seq4[0] == 3.0 -import macros -seq4 = - if i > 0: newMySeq(2, 5.0) - elif i < -100: raise newException(ValueError, "Parse Error") - else: newMySeq(2, 3.0) + seq4 = + if i > 0: newMySeq(2, 5.0) + elif i < -100: raise newException(ValueError, "Parse Error") + else: newMySeq(2, 3.0) -seq4 = - case (char) i: - of 'A', {'W'..'Z'}: newMySeq(2, 5.0) - of 'B': quit(-1) - else: - let (x1, x2, x3) = myfunc2(2, 3) - x3 + seq4 = + case (char) i: + of 'A', {'W'..'Z'}: newMySeq(2, 5.0) + of 'B': quit(-1) + else: + let (x1, x2, x3) = myfunc2(2, 3) + x3 +foo() #------------------------------------------------------------ #-- Move into array constructor @@ -179,7 +179,7 @@ proc myfuncLoop(x: int): MySeqNonCopyable = discard myfuncLoop(3) #------------------------------------------------------------ -# Move into table via openarray +# Move into table via openArray #------------------------------------------------------------ type diff --git a/tests/destructor/tnewruntime_misc.nim b/tests/destructor/tnewruntime_misc.nim index 1a5b0e3b0..21c70557d 100644 --- a/tests/destructor/tnewruntime_misc.nim +++ b/tests/destructor/tnewruntime_misc.nim @@ -7,7 +7,7 @@ axc ... destroying GenericObj[T] GenericObj[system.int] test -(allocCount: 13, deallocCount: 11) +(allocCount: 12, deallocCount: 10) 3''' """ @@ -25,8 +25,13 @@ putEnv("HEAPTRASHING", "Indeed") let s1 = getAllocStats() + +proc newTableOwned[A, B](initialSize = defaultInitialSize): owned(TableRef[A, B]) = + new(result) + result[] = initTable[A, B](initialSize) + proc main = - var w = newTable[string, owned Node]() + var w = newTableOwned[string, owned Node]() w["key"] = Node(field: "value") echo w["key"][] echo getEnv("HEAPTRASHING") @@ -132,7 +137,16 @@ proc xx(xml: string): MyObject = discard xx("test") -echo getAllocStats() - s1 + +# Windows has 1 extra allocation in `getEnv` - there it allocates parameter to +# `_wgetenv` (WideCString). Therefore subtract by 1 to match other OSes' +# allocation. +when defined(windows): + import std/importutils + privateAccess(AllocStats) + echo getAllocStats() - s1 - AllocStats(allocCount: 1, deallocCount: 1) +else: + echo getAllocStats() - s1 # bug #13457 var s = "abcde" diff --git a/tests/destructor/tnewruntime_strutils.nim b/tests/destructor/tnewruntime_strutils.nim index b0bceb4b5..9c8d41973 100644 --- a/tests/destructor/tnewruntime_strutils.nim +++ b/tests/destructor/tnewruntime_strutils.nim @@ -1,8 +1,12 @@ discard """ valgrind: true - cmd: '''nim c -d:nimAllocStats --newruntime -d:useMalloc $file''' + cmd: '''nim c -d:nimAllocStats --gc:arc -d:useMalloc $file''' output: ''' -@[(input: @["KXSC", "BGMC"]), (input: @["PXFX"]), (input: @["WXRQ", "ZSCZD"])]''' +@[(input: @["KXSC", "BGMC"]), (input: @["PXFX"]), (input: @["WXRQ", "ZSCZD"])] +14 +First tasks completed. +Second tasks completed. +test1''' """ import strutils, os, std / wordwrap @@ -211,3 +215,40 @@ staticTests() # bug #12965 let xaa = @[""].join() let xbb = @["", ""].join() + +# bug #16365 + +# Task 1: +when true: + # Task 1_a: + var test_string_a = "name_something" + echo test_string_a.len() + let new_len_a = test_string_a.len - "_something".len() + test_string_a.setLen new_len_a + + echo "First tasks completed." + +# Task 2: +when true: + # Task 2_a + var test_string: string + let some_string = "something" + for i in some_string.items: + test_string.add $i + + # Task 2_b + var test_string_b = "name_something" + let new_len_b = test_string_b.len - "_something".len() + test_string_b.setLen new_len_b + + echo "Second tasks completed." + +# bug #17450 +proc main = + var i = 1 + echo: + block: + "test" & $i + +main() + diff --git a/tests/destructor/tnonvardestructor.nim b/tests/destructor/tnonvardestructor.nim new file mode 100644 index 000000000..1b4413790 --- /dev/null +++ b/tests/destructor/tnonvardestructor.nim @@ -0,0 +1,247 @@ +discard """ + targets: "c cpp" + matrix: "--mm:arc; --mm:orc" +""" + +block: + type + PublicKey = array[32, uint8] + PrivateKey = array[64, uint8] + + proc ed25519_create_keypair(publicKey: ptr PublicKey; privateKey: ptr PrivateKey) = + publicKey[][0] = uint8(88) + + type + KeyPair = object + public: PublicKey + private: PrivateKey + + proc initKeyPair(): KeyPair = + ed25519_create_keypair(result.public.addr, result.private.addr) + + let keys = initKeyPair() + doAssert keys.public[0] == 88 + + +template minIndexByIt: untyped = + var other = 3 + other + +proc bug20303() = + var hlibs = @["hello", "world", "how", "are", "you"] + let res = hlibs[minIndexByIt()] + doAssert res == "are" + +bug20303() + +proc main() = # todo bug with templates + block: # bug #11267 + var a: seq[char] = block: @[] + doAssert a == @[] + # 2 + proc b: seq[string] = + discard + @[] + doAssert b() == @[] +static: main() +main() + + +type Obj = tuple + value: int + arr: seq[int] + +proc bug(): seq[Obj] = + result.add (value: 0, arr: @[]) + result[^1].value = 1 + result[^1].arr.add 1 + +# bug #19990 +let s = bug() +doAssert s[0] == (value: 1, arr: @[1]) + +block: # bug #21974 + type Test[T] = ref object + values : seq[T] + counter: int + + proc newTest[T](): Test[T] = + result = new(Test[T]) + result.values = newSeq[T](16) + result.counter = 0 + + proc push[T](self: Test[T], value: T) = + self.counter += 1 + if self.counter >= self.values.len: + self.values.setLen(self.values.len * 2) + self.values[self.counter - 1] = value + + proc pop[T](self: Test[T]): T = + result = self.values[0] + self.values[0] = self.values[self.counter - 1] # <--- This line + self.counter -= 1 + + + type X = tuple + priority: int + value : string + + var a = newTest[X]() + a.push((1, "One")) + doAssert a.pop.value == "One" + +# bug #21987 + +type + EmbeddedImage* = distinct Image + Image = object + len: int + +proc imageCopy*(image: Image): Image {.nodestroy.} + +proc `=destroy`*(x: Image) = + discard + +proc `=sink`*(dest: var Image; source: Image) = + `=destroy`(dest) + wasMoved(dest) + +proc `=dup`*(source: Image): Image {.nodestroy.} = + result = imageCopy(source) + +proc `=copy`*(dest: var Image; source: Image) = + dest = imageCopy(source) # calls =sink implicitly + +proc `=destroy`*(x: EmbeddedImage) = discard + +proc `=dup`*(source: EmbeddedImage): EmbeddedImage {.nodestroy.} = source + +proc `=copy`*(dest: var EmbeddedImage; source: EmbeddedImage) {.nodestroy.} = + dest = source + +proc imageCopy*(image: Image): Image = + result = image + +proc main2 = + block: + var a = Image(len: 2).EmbeddedImage + var b = Image(len: 1).EmbeddedImage + b = a + doAssert Image(a).len == 2 + doAssert Image(b).len == 2 + + block: + var a = Image(len: 2) + var b = Image(len: 1) + b = a + doAssert a.len == 2 + doAssert b.len == 0 + +main2() + +type + Edge = object + neighbor {.cursor.}: Node + + NodeObj = object + neighbors: seq[Edge] + label: string + visited: bool + Node = ref NodeObj + + Graph = object + nodes: seq[Node] + +proc `=destroy`(x: NodeObj) = + `=destroy`(x.neighbors) + `=destroy`(x.label) + +proc addNode(self: var Graph; label: string): Node = + self.nodes.add(Node(label: label)) + result = self.nodes[^1] + +proc addEdge(self: Graph; source, neighbor: Node) = + source.neighbors.add(Edge(neighbor: neighbor)) + +block: + proc main = + var graph: Graph + let nodeA = graph.addNode("a") + let nodeB = graph.addNode("b") + let nodeC = graph.addNode("c") + + graph.addEdge(nodeA, neighbor = nodeB) + graph.addEdge(nodeA, neighbor = nodeC) + + main() + +block: + type RefObj = ref object + + proc `[]`(val: static[int]) = # works with different name/overload or without static arg + discard + + template noRef(T: typedesc): typedesc = # works without template indirection + typeof(default(T)[]) + + proc `=destroy`(x: noRef(RefObj)) = + discard + + proc foo = + var x = new RefObj + doAssert $(x[]) == "()" + + # bug #11705 + foo() + +block: # bug #22197 + type + H5IdObj = object + H5Id = ref H5IdObj + + FileID = distinct H5Id + + H5GroupObj = object + file_id: FileID + H5Group = ref H5GroupObj + + ## This would make it work! + #proc `=destroy`*(x: FileID) = `=destroy`(cast[H5Id](x)) + ## If this does not exist, it also works! + proc newFileID(): FileID = FileID(H5Id()) + + proc `=destroy`(grp: H5GroupObj) = + ## Closes the group and resets all references to nil. + if cast[pointer](grp.fileId) != nil: + `=destroy`(grp.file_id) + + var grp = H5Group() + reset(grp.file_id) + reset(grp) + +import std/tables + +block: # bug #22286 + type + A = object + B = object + a: A + C = object + b: B + + proc `=destroy`(self: A) = + echo "destroyed" + + proc `=destroy`(self: C) = + `=destroy`(self.b) + + var c = C() + +block: # https://forum.nim-lang.org/t/10642 + type AObj = object + name: string + tableField: Table[string, string] + + proc `=destroy`(x: AObj) = + `=destroy`(x.name) + `=destroy`(x.tableField) diff --git a/tests/destructor/topttree.nim b/tests/destructor/topttree.nim index fa5495689..8cf757e8b 100644 --- a/tests/destructor/topttree.nim +++ b/tests/destructor/topttree.nim @@ -1,4 +1,5 @@ discard """ + disabled: i386 output: '''10.0 60.0 90.0 diff --git a/tests/destructor/towned_binary_tree.nim b/tests/destructor/towned_binary_tree.nim index 320e33759..fb635e7c6 100644 --- a/tests/destructor/towned_binary_tree.nim +++ b/tests/destructor/towned_binary_tree.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c -d:nimAllocStats --newruntime $file''' + cmd: '''nim c -d:nimAllocStats --gc:arc $file''' output: '''31665 (allocCount: 33334, deallocCount: 33334)''' """ diff --git a/tests/destructor/tprevent_assign.nim b/tests/destructor/tprevent_assign.nim index 108ccc371..4c484ebc1 100644 --- a/tests/destructor/tprevent_assign.nim +++ b/tests/destructor/tprevent_assign.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'" + errormsg: "'=copy' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'" line: 29 """ diff --git a/tests/destructor/tprevent_assign2.nim b/tests/destructor/tprevent_assign2.nim index 0e4481710..eb5588b1a 100644 --- a/tests/destructor/tprevent_assign2.nim +++ b/tests/destructor/tprevent_assign2.nim @@ -1,7 +1,7 @@ discard """ - errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'" + errormsg: "'=dup' is not available for type <Foo>, which is inferred from unavailable '=copy'; requires a copy because it's not the last read of 'otherTree'; another read is done here: tprevent_assign2.nim(51, 31); routine: preventThis" file: "tprevent_assign2.nim" - line: 48 + line: 49 """ type @@ -9,7 +9,8 @@ type x: int proc `=destroy`(f: var Foo) = f.x = 0 -proc `=`(a: var Foo; b: Foo) {.error.} # = a.x = b.x +proc `=copy`(a: var Foo; b: Foo) {.error.} # = a.x = b.x + proc `=sink`(a: var Foo; b: Foo) = a.x = b.x proc createTree(x: int): Foo = @@ -18,7 +19,7 @@ proc createTree(x: int): Foo = proc take2(a, b: sink Foo) = echo a.x, " ", b.x -proc allowThis() = +when false: var otherTree: Foo try: for i in 0..3: @@ -51,5 +52,5 @@ proc preventThis() = else: discard -allowThis() +#allowThis() preventThis() diff --git a/tests/destructor/tprevent_assign3.nim b/tests/destructor/tprevent_assign3.nim index a8a35ea5e..aa834a66c 100644 --- a/tests/destructor/tprevent_assign3.nim +++ b/tests/destructor/tprevent_assign3.nim @@ -1,7 +1,7 @@ discard """ - errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'" + errormsg: "'=dup' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'" file: "tprevent_assign3.nim" - line: 46 + line: 47 """ type @@ -9,7 +9,8 @@ type x: int proc `=destroy`(f: var Foo) = f.x = 0 -proc `=`(a: var Foo; b: Foo) {.error.} # = a.x = b.x +proc `=copy`(a: var Foo; b: Foo) {.error.} # = a.x = b.x +proc `=dup`(a: Foo): Foo {.error.} proc `=sink`(a: var Foo; b: Foo) = a.x = b.x proc createTree(x: int): Foo = @@ -18,7 +19,7 @@ proc createTree(x: int): Foo = proc take2(a, b: sink Foo) = echo a.x, " ", b.x -proc allowThis() = +when false: var otherTree: Foo try: for i in 0..3: @@ -47,7 +48,7 @@ proc preventThis2() = finally: echo otherTree -allowThis() +#allowThis() preventThis2() diff --git a/tests/destructor/trecursive.nim b/tests/destructor/trecursive.nim index 17a40e5a9..e7afa6ba9 100644 --- a/tests/destructor/trecursive.nim +++ b/tests/destructor/trecursive.nim @@ -47,7 +47,7 @@ proc `=destroy`(x: var MyObject) = proc `=`(x: var MyObject, y: MyObject) {.error.} proc newMyObject(i: int): MyObject = - result.p = create(int) + result.p = createShared(int) result.p[] = i proc test: seq[MyObject] = diff --git a/tests/destructor/tsimpleclosure.nim b/tests/destructor/tsimpleclosure.nim index 35c57a634..9626dd6f8 100644 --- a/tests/destructor/tsimpleclosure.nim +++ b/tests/destructor/tsimpleclosure.nim @@ -1,5 +1,5 @@ discard """ - cmd: '''nim c -d:nimAllocStats --newruntime $file''' + cmd: '''nim c -d:nimAllocStats --gc:arc $file''' output: '''a b 70 hello diff --git a/tests/destructor/tsink.nim b/tests/destructor/tsink.nim new file mode 100644 index 000000000..e8750ad7c --- /dev/null +++ b/tests/destructor/tsink.nim @@ -0,0 +1,70 @@ +discard """ + matrix: "--mm:arc" +""" + +type AnObject = object of RootObj + value*: int + +proc mutate(shit: sink AnObject) = + shit.value = 1 + +proc foo = # bug #23359 + var bar = AnObject(value: 42) + mutate(bar) + doAssert bar.value == 42 + +foo() + +block: # bug #23902 + proc foo(a: sink string): auto = (a, a) + + proc bar(a: sink int): auto = return a + + proc foo(a: sink string) = + var x = (a, a) + +block: # bug #24175 + block: + func mutate(o: sink string): string = + o[1] = '1' + result = o + + static: + let s = "999" + let m = mutate(s) + doAssert s == "999" + doAssert m == "919" + + func foo() = + let s = "999" + let m = mutate(s) + doAssert s == "999" + doAssert m == "919" + + static: + foo() + foo() + + block: + type O = object + a: int + + func mutate(o: sink O): O = + o.a += 1 + o + + static: + let x = O(a: 1) + let y = mutate(x) + doAssert x.a == 1 + doAssert y.a == 2 + + proc foo() = + let x = O(a: 1) + let y = mutate(x) + doAssert x.a == 1 + doAssert y.a == 2 + + static: + foo() + foo() diff --git a/tests/destructor/ttuple.nim b/tests/destructor/ttuple.nim index 5a2126105..d0ea72c60 100644 --- a/tests/destructor/ttuple.nim +++ b/tests/destructor/ttuple.nim @@ -2,7 +2,7 @@ discard """ output: '''5.0 10.0 =destroy -=destroy +=destroy ''' """ diff --git a/tests/destructor/tuse_ownedref_after_move.nim b/tests/destructor/tuse_ownedref_after_move.nim index 46540837c..69348d530 100644 --- a/tests/destructor/tuse_ownedref_after_move.nim +++ b/tests/destructor/tuse_ownedref_after_move.nim @@ -1,6 +1,6 @@ discard """ cmd: '''nim c --newruntime $file''' - errormsg: "'=' is not available for type <owned Button>; requires a copy because it's not the last read of ':envAlt.b1'; another read is done here: tuse_ownedref_after_move.nim(52, 4)" + errormsg: "'=copy' is not available for type <owned Button>; requires a copy because it's not the last read of ':envAlt.b1'; routine: main" line: 48 """ diff --git a/tests/destructor/tuse_result_prevents_sinks.nim b/tests/destructor/tuse_result_prevents_sinks.nim index 37b5af9b2..e74c16da3 100644 --- a/tests/destructor/tuse_result_prevents_sinks.nim +++ b/tests/destructor/tuse_result_prevents_sinks.nim @@ -1,6 +1,6 @@ discard """ output: "" - target: "C" + targets: "c" """ # bug #9594 @@ -17,15 +17,20 @@ proc `=sink`(self: var Foo; other: Foo) = proc `=destroy`(self: var Foo) = discard +template preventCursorInference(x) = + let p = addr(x) + proc test(): Foo = result = Foo() let temp = result + preventCursorInference temp doAssert temp.i > 0 return result proc testB(): Foo = result = Foo() let temp = result + preventCursorInference temp doAssert temp.i > 0 discard test() diff --git a/tests/destructor/tv2_cast.nim b/tests/destructor/tv2_cast.nim index 9c05b2ae1..48bdf67dd 100644 --- a/tests/destructor/tv2_cast.nim +++ b/tests/destructor/tv2_cast.nim @@ -1,10 +1,81 @@ discard """ - cmd: '''nim c --newruntime $file''' output: '''@[1] @[116, 101, 115, 116] -@[1953719668, 875770417]''' +@[1953719668, 875770417] +destroying O1''' + cmd: '''nim c --mm:arc --expandArc:main --expandArc:main1 --expandArc:main2 --expandArc:main3 --hints:off --assertions:off $file''' + nimout: ''' +--expandArc: main + +var + data + :tmpD +data = cast[string](encode(cast[seq[byte]]( + :tmpD = newString(100) + :tmpD))) +`=destroy`(:tmpD) +`=destroy`(data) +-- end of expandArc ------------------------ +--expandArc: main1 + +var + s + data +s = newString(100) +data = cast[string](encode(toOpenArrayByte(s, 0, len(s) - 1))) +`=destroy`(data) +`=destroy`(s) +-- end of expandArc ------------------------ +--expandArc: main2 + +var + s + data +s = newSeq(100) +data = cast[string](encode(s)) +`=destroy`(data) +`=destroy_1`(s) +-- end of expandArc ------------------------ +--expandArc: main3 + +var + data + :tmpD +data = cast[string](encode do: + :tmpD = newSeq(100) + :tmpD) +`=destroy`(:tmpD) +`=destroy_1`(data) +-- end of expandArc ------------------------ +''' """ +func encode*(src: openArray[byte]): seq[byte] = + result = newSeq[byte](src.len) + +template compress*(src: string): string = + cast[string](encode(cast[seq[byte]](src))) + +proc main = + let data = compress(newString(100)) +main() + +proc main1 = + var + s = newString(100) + let data = cast[string](encode(s.toOpenArrayByte(0, s.len-1))) +main1() + +proc main2 = + var + s = newSeq[byte](100) + let data = cast[string](encode(s)) +main2() + +proc main3 = + let data = cast[string](encode(newSeq[byte](100))) +main3() + # bug #11018 discard cast[seq[uint8]](@[1]) discard cast[seq[uint8]]("test") @@ -20,4 +91,26 @@ echo a #issue 11204 var ac {.compileTime.} = @["a", "b"] -const bc = ac.len \ No newline at end of file +const bc = ac.len + + +type + O = object of RootRef + i: int + + O1 = object of O + O2 = object of O + +proc `=destroy`(o: var O) = + echo "destroying O" + +proc `=destroy`(o: var O1) = + echo "destroying O1" + +proc `=destroy`(o: var O2) = + echo "destroying O2" + +proc test = + let o3 = cast[ref O2]((ref O1)()) + +test() diff --git a/tests/destructor/twasmoved.nim b/tests/destructor/twasmoved.nim new file mode 100644 index 000000000..566322702 --- /dev/null +++ b/tests/destructor/twasmoved.nim @@ -0,0 +1,14 @@ +type + Foo = object + id: int + +proc `=wasMoved`(x: var Foo) = + x.id = -1 + +proc foo = + var s = Foo(id: 999) + var m = move s + doAssert s.id == -1 + doAssert m.id == 999 + +foo() diff --git a/tests/destructor/twasmoved_error.nim b/tests/destructor/twasmoved_error.nim new file mode 100644 index 000000000..1cd57e3df --- /dev/null +++ b/tests/destructor/twasmoved_error.nim @@ -0,0 +1,37 @@ +discard """ + cmd: '''nim c --mm:arc $file''' + errormsg: "'=wasMoved' is not available for type <Game>; routine: main" +""" + +# bug #19291 + +const + screenWidth = 800 + screenHeight = 450 + +var + ready = false +type + Game = object + +proc `=destroy`(x: var Game) = + assert ready, "Window is already opened" + ready = false + +proc `=sink`(x: var Game; y: Game) {.error.} +proc `=copy`(x: var Game; y: Game) {.error.} +proc `=wasMoved`(x: var Game) {.error.} + +proc initGame(width, height: int32, title: string): Game = + assert not ready, "Window is already closed" + ready = true + +proc update(x: Game) = discard + +proc main = + var g = initGame(screenWidth, screenHeight, "Tetris raylib") + g.update() + var g2 = g + echo "hello" + +main() |