diff options
Diffstat (limited to 'tests/destructor')
64 files changed, 1384 insertions, 163 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 1acc95fad..54d75a410 100644 --- a/tests/destructor/tarc.nim +++ b/tests/destructor/tarc.nim @@ -6,7 +6,11 @@ Success Hello 1 2 -0''' +0 +List +@["4", "5", "6", "", "", "a", ""] +@["", "", "a", ""] +''' cmd: '''nim c --gc:arc $file''' """ @@ -145,3 +149,36 @@ proc bug13105 = bug13105() echo getOccupiedMem() - startMem + + +#------------------------------------------------------------------------------ +# issue #14294 + +import tables + +type + TagKind = enum + List = 0, Compound + + Tag = object + case kind: TagKind + of List: + values: seq[Tag] + 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/tarc2.nim b/tests/destructor/tarc2.nim index bd6343b2f..a7d7b4945 100644 --- a/tests/destructor/tarc2.nim +++ b/tests/destructor/tarc2.nim @@ -13,9 +13,13 @@ proc create(): T = T(s: @[], data: "abc") proc addX(x: T; data: string) = x.data = data +{.push sinkInference: off.} + proc addX(x: T; child: T) = x.s.add child +{.pop.} + proc main(rootName: string) = var root = create() root.data = rootName @@ -23,4 +27,5 @@ proc main(rootName: string) = let mem = getOccupiedMem() main("yeah") +GC_fullCollect() echo "leak: ", getOccupiedMem() - mem > 0 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/tasync_prototype.nim b/tests/destructor/tasync_prototype.nim index bd80adf0c..81fd824e9 100644 --- a/tests/destructor/tasync_prototype.nim +++ b/tests/destructor/tasync_prototype.nim @@ -32,7 +32,12 @@ proc serve(server: PAsyncHttpServer): PFutureBase = yield acceptAddrFut var fut = acceptAddrFut.value + # with the new scope based destruction, this cannot + # possibly work: var f {.cursor.} = processClient() + # It also seems to be the wrong way how to avoid the + # cycle. The cycle is caused by capturing the 'env' + # part from 'env.f'. when true: f.callback = proc () = diff --git a/tests/destructor/tasync_prototype_cyclic.nim b/tests/destructor/tasync_prototype_cyclic.nim index 136e0b676..8ba73a8fc 100644 --- a/tests/destructor/tasync_prototype_cyclic.nim +++ b/tests/destructor/tasync_prototype_cyclic.nim @@ -51,4 +51,5 @@ proc main = discard serve(PAsyncHttpServer(value: "asdas")) main() +GC_fullCollect() echo "MEMORY ", getOccupiedMem() - mem 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 e910f430a..d56c2850b 100644 --- a/tests/destructor/tbintree2.nim +++ b/tests/destructor/tbintree2.nim @@ -1,7 +1,7 @@ discard """ cmd: '''nim c -d:nimAllocStats --newruntime $file''' output: '''0 -(allocCount: 6, deallocCount: 6)''' +(allocCount: 5, deallocCount: 5)''' """ import system / ansi_c @@ -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 8687b3ce5..b0a039e9b 100644 --- a/tests/destructor/tconsume_twice.nim +++ b/tests/destructor/tconsume_twice.nim @@ -1,7 +1,7 @@ discard """ cmd: "nim c --newruntime $file" - errormsg: "sink parameter `a` is already consumed at tconsume_twice.nim(11, 10)" - line: 13 + 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 Foo = ref object 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/tcycle1.nim b/tests/destructor/tcycle1.nim index c30977433..8dc552294 100644 --- a/tests/destructor/tcycle1.nim +++ b/tests/destructor/tcycle1.nim @@ -50,4 +50,5 @@ proc main = let mem = getOccupiedMem() main() +GC_fullCollect() echo "MEM ", getOccupiedMem() - mem diff --git a/tests/destructor/tcycle2.nim b/tests/destructor/tcycle2.nim index c4b297559..7b03101fe 100644 --- a/tests/destructor/tcycle2.nim +++ b/tests/destructor/tcycle2.nim @@ -13,6 +13,24 @@ proc main(x: int) = let m = n n.kids.add m +type + NodeA = ref object + s: char + a: array[3, NodeA] + +proc m: NodeA = + result = NodeA(s: 'a') + result.a[0] = result + result.a[1] = result + result.a[2] = result + +proc mainA = + for i in 0..10: + discard m() + let mem = getOccupiedMem() main(90) +mainA() +GC_fullCollect() + echo "MEM ", getOccupiedMem() - mem diff --git a/tests/destructor/tcycle3.nim b/tests/destructor/tcycle3.nim index a938ded01..8662136e7 100644 --- a/tests/destructor/tcycle3.nim +++ b/tests/destructor/tcycle3.nim @@ -2,6 +2,8 @@ discard """ output: '''BEGIN END END 2 +cpu.nes false +cpu step nes is nil? - false 0''' cmd: '''nim c --gc:orc $file''' """ @@ -59,6 +61,38 @@ proc main = c.run echo "END 2" +# bug #14159 +type + NES = ref object + cpu: CPU + apu: APU + + CPU = ref object + nes: NES + + APU = object + nes: NES + cpu: CPU + +proc initAPU(nes: sink NES): APU {.nosinks.} = + result.nes = nes + result.cpu = nes.cpu + +proc step(cpu: CPU): int = + echo "cpu.nes ", cpu.isNil + echo "cpu step nes is nil? - ", cpu.nes.isNil() + +proc newNES(): NES = + new result + result.cpu = CPU(nes: result) + result.apu = initAPU(result) + +proc bug14159 = + var nesConsole = newNES() + discard nesConsole.cpu.step() + let mem = getOccupiedMem() main() +bug14159() +GC_fullCollect() echo getOccupiedMem() - mem diff --git a/tests/destructor/tdestructor.nim b/tests/destructor/tdestructor.nim index 5cfecea4e..e081eb251 100644 --- a/tests/destructor/tdestructor.nim +++ b/tests/destructor/tdestructor.nim @@ -1,27 +1,27 @@ discard """ - output: '''---- + output: '''----1 myobj constructed myobj destroyed ----- +----2 mygeneric1 constructed mygeneric1 destroyed ----- +----3 mygeneric2 constructed mygeneric2 destroyed myobj destroyed ----- +----4 mygeneric3 constructed mygeneric1 destroyed ----- +----5 mydistinctObj constructed myobj destroyed mygeneric2 destroyed ------------------- ----- ----- -myobj destroyed +------------------8 mygeneric1 destroyed ---- +----6 +myobj destroyed +----7 +---9 myobj destroyed myobj destroyed ''' @@ -33,7 +33,7 @@ type p: pointer proc `=destroy`(o: var TMyObj) = - if o.p != nil: + if o.p != nil: dealloc o.p o.p = nil echo "myobj destroyed" @@ -114,19 +114,19 @@ proc mydistinctObj = echo "mydistinctObj constructed" -echo "----" +echo "----1" myobj() -echo "----" +echo "----2" mygeneric1() -echo "----" +echo "----3" mygeneric2[int](10) -echo "----" +echo "----4" mygeneric3() -echo "----" +echo "----5" mydistinctObj() proc caseobj = @@ -134,16 +134,16 @@ proc caseobj = var o1 = TCaseObj(kind: A, x: TMyGeneric1[int](x: 10)) block: - echo "----" + echo "----6" var o2 = TCaseObj(kind: B, y: open()) block: - echo "----" + echo "----7" var o3 = TCaseObj(kind: D, innerKind: B, r: "test", p: TMyGeneric3[int, float, string](x: 10, y: 1.0, z: "test")) -echo "------------------" +echo "------------------8" caseobj() proc caseobj_test_sink: TCaseObj = @@ -153,5 +153,15 @@ proc caseobj_test_sink: TCaseObj = result = TCaseObj(kind: B, y: open()) -echo "---" -discard caseobj_test_sink() \ No newline at end of file +echo "---9" +discard caseobj_test_sink() + +# issue #14315 + +type Vector*[T] = object + x1: int + # x2: T # uncomment will remove error + +# proc `=destroy`*(x: var Vector[int]) = discard # this will remove error +proc `=destroy`*[T](x: var Vector[T]) = discard +var a: Vector[int] # Error: unresolved generic parameter 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/tfinalizer.nim b/tests/destructor/tfinalizer.nim index 02a5cef7e..eb2cd09af 100644 --- a/tests/destructor/tfinalizer.nim +++ b/tests/destructor/tfinalizer.nim @@ -1,6 +1,6 @@ discard """ cmd: "nim c --gc:arc $file" - output: '''Foo(field: Dick Laurent, k: ka, x: 0.0) + output: '''Foo(field: "Dick Laurent", k: ka, x: 0.0) Nobody is dead Dick Laurent is dead''' """ diff --git a/tests/destructor/tgcdestructors.nim b/tests/destructor/tgcdestructors.nim index 7169daaf1..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 @@ -10,7 +10,7 @@ a: @[4, 2, 3] 0 30 true -(allocCount: 41, deallocCount: 41)''' +(allocCount: 27, deallocCount: 27)''' """ include system / ansi_c 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/tgotoexceptions4.nim b/tests/destructor/tgotoexceptions4.nim index 918169084..b2b481256 100644 --- a/tests/destructor/tgotoexceptions4.nim +++ b/tests/destructor/tgotoexceptions4.nim @@ -4,7 +4,9 @@ discard """ caught in fun caughtsome msgMyExcept in finally -caught1''' +caught1 +123 +123''' """ when true: @@ -38,3 +40,21 @@ when true: except CatchableError: echo "caught1" funB() + +# bug #13782 + +import strutils +var n = 123 + +try: n = parseInt("xxx") +except: discard + +echo n + +proc sameTestButForLocalVar = + var n = 123 + try: n = parseInt("xxx") + except: discard + echo n + +sameTestButForLocalVar() diff --git a/tests/destructor/tgotoexceptions5.nim b/tests/destructor/tgotoexceptions5.nim new file mode 100644 index 000000000..695aab0a4 --- /dev/null +++ b/tests/destructor/tgotoexceptions5.nim @@ -0,0 +1,45 @@ +discard """ + output: ''' +before +swallowed +before +swallowed B +''' + cmd: "nim c --gc:arc --exceptions:goto -d:ssl $file" +""" + +# bug #13599 +proc main() = + try: + echo "before" + raise newException(CatchableError, "foo") + except AssertionDefect: + echo "caught" + echo "after" + +try: + main() +except: + echo "swallowed" + +proc mainB() = + try: + echo "before" + raise newException(CatchableError, "foo") + # except CatchableError: # would work + except AssertionDefect: + echo "caught" + except: + raise + echo "after" + +try: + mainB() +except: + echo "swallowed B" + +# bug #14647 +import httpclient + +newAsyncHttpClient().close() + diff --git a/tests/destructor/tgotoexceptions6.nim b/tests/destructor/tgotoexceptions6.nim new file mode 100644 index 000000000..7c01f6a52 --- /dev/null +++ b/tests/destructor/tgotoexceptions6.nim @@ -0,0 +1,10 @@ +discard """ + cmd: "nim c --gc:arc --exceptions:goto $file" + outputsub: "Error: unhandled exception: virus detected [ValueError]" + exitcode: "1" +""" + +# bug #13436 +proc foo = + raise newException(ValueError, "virus detected") +foo() diff --git a/tests/destructor/tgotoexceptions7.nim b/tests/destructor/tgotoexceptions7.nim new file mode 100644 index 000000000..c04bd6ba0 --- /dev/null +++ b/tests/destructor/tgotoexceptions7.nim @@ -0,0 +1,49 @@ +discard """ + cmd: "nim c --gc:arc --exceptions:goto --panics:off $file" + output: '''prevented! +caught +AssertionDefect +900''' +""" + +type + E = enum + kindA, kindB + Obj = object + case kind: E + of kindA: s: string + of kindB: i: int + + ObjA = ref object of RootObj + ObjB = ref object of ObjA + +proc takeRange(x: range[0..4]) = discard + +proc bplease(x: ObjB) = discard + +proc helper = doAssert(false) + +proc main(i: int) = + var obj = Obj(kind: kindA, s: "abc") + {.cast(uncheckedAssign).}: + obj.kind = kindB + obj.i = 2 + try: + var objA = ObjA() + bplease(ObjB(objA)) + except ObjectConversionDefect: + echo "prevented!" + + try: + takeRange(i) + except RangeDefect: + echo "caught" + + try: + helper() + except AssertionDefect: + echo "AssertionDefect" + + echo i * i + +main(30) diff --git a/tests/destructor/tgotoexceptions8.nim b/tests/destructor/tgotoexceptions8.nim new file mode 100644 index 000000000..8ed2ed0ba --- /dev/null +++ b/tests/destructor/tgotoexceptions8.nim @@ -0,0 +1,76 @@ +discard """ + output: '''A +B +X +inner finally +Y +outer finally +msg1 +msg2 +finally2 +finally1 +true''' + cmd: "nim c --gc:arc $file" +""" + +# bug #13668 + +proc main = + try: + try: + raise newException(IOError, "IOError") + + except: + echo "A" + raise newException(CatchableError, "CatchableError") + + except: + echo "B" + #discard + +proc mainB = + try: + try: + raise newException(IOError, "IOError") + + except: + echo "X" + raise newException(CatchableError, "CatchableError") + finally: + echo "inner finally" + + except: + echo "Y" + #discard + finally: + echo "outer finally" + +main() +mainB() + +when true: + #bug 7204 + proc nested_finally = + try: + raise newException(KeyError, "msg1") + except KeyError as ex: + echo ex.msg + try: + # pop exception + raise newException(ValueError, "msg2") # push: exception stack (1 entry) + except: + echo getCurrentExceptionMsg() + # pop exception (except) + finally: + echo "finally2" + # pop exception (except KeyError as ex) + finally: + 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 53c67e34b..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 5b2198e51..cdc1eb1c0 100644 --- a/tests/destructor/tmove_objconstr.nim +++ b/tests/destructor/tmove_objconstr.nim @@ -8,7 +8,7 @@ test destroyed 0 4 Pony is dying!''' joinable: false -target: "C" +targets: "c" """ # bug #4214 @@ -50,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: @@ -112,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), @@ -137,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 @@ -178,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 263ea1bd4..21c70557d 100644 --- a/tests/destructor/tnewruntime_misc.nim +++ b/tests/destructor/tnewruntime_misc.nim @@ -7,7 +7,8 @@ axc ... destroying GenericObj[T] GenericObj[system.int] test -(allocCount: 17, deallocCount: 15)''' +(allocCount: 12, deallocCount: 10) +3''' """ import system / ansi_c @@ -24,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") @@ -131,4 +137,19 @@ 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" +s.setLen(3) + +echo s.cstring.len diff --git a/tests/destructor/tnewruntime_strutils.nim b/tests/destructor/tnewruntime_strutils.nim index 9afb507f7..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 @@ -37,7 +41,7 @@ bug12899() proc nonStaticTests = doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000" - doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235" # bugs 8242, 12586 + doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." # bugs 8242, 12586 doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6" doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001" doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in @@ -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 3ec80badf..fb635e7c6 100644 --- a/tests/destructor/towned_binary_tree.nim +++ b/tests/destructor/towned_binary_tree.nim @@ -1,7 +1,7 @@ discard """ - cmd: '''nim c -d:nimAllocStats --newruntime $file''' - output: '''331665 -(allocCount: 333335, deallocCount: 333335)''' + cmd: '''nim c -d:nimAllocStats --gc:arc $file''' + output: '''31665 +(allocCount: 33334, deallocCount: 33334)''' """ # bug #11053 @@ -72,7 +72,7 @@ proc main() = cur = 5'i32 res = 0 - for i in 1 ..< 1000000: + for i in 1 ..< 100000: let a = i mod 3 cur = (cur * 57 + 43) mod 10007 case a: 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 55e67f52a..e7afa6ba9 100644 --- a/tests/destructor/trecursive.nim +++ b/tests/destructor/trecursive.nim @@ -32,3 +32,29 @@ proc test1() = echo "test1 OK" test1() + +#------------------------------------------------------------------------------ +# issue #14217 + +type + MyObject = object + p: ptr int + +proc `=destroy`(x: var MyObject) = + if x.p != nil: + deallocShared(x.p) + +proc `=`(x: var MyObject, y: MyObject) {.error.} + +proc newMyObject(i: int): MyObject = + result.p = createShared(int) + result.p[] = i + +proc test: seq[MyObject] = + for i in 0..3: + let x = newMyObject(i) + result.add x + +var x = test() +for i in 0..3: + doAssert(x[i].p[] == i) diff --git a/tests/destructor/tselect.nim b/tests/destructor/tselect.nim index 9262b47d4..c22bf7203 100644 --- a/tests/destructor/tselect.nim +++ b/tests/destructor/tselect.nim @@ -1,6 +1,9 @@ discard """ output: '''abcsuffix -xyzsuffix''' +xyzsuffix +destroy foo 2 +destroy foo 1 +''' cmd: '''nim c --gc:arc $file''' """ @@ -24,3 +27,24 @@ proc test(param: string; cond: bool) = test("suffix", true) test("suffix", false) + + + +#-------------------------------------------------------------------- +# issue #13659 + +type + Foo = ref object + data: int + parent: Foo + +proc `=destroy`(self: var type(Foo()[])) = + echo "destroy foo ", self.data + for i in self.fields: i.reset + +proc getParent(self: Foo): Foo = self.parent + +var foo1 = Foo(data: 1) +var foo2 = Foo(data: 2, parent: foo1) + +foo2.getParent.data = 1 \ No newline at end of file diff --git a/tests/destructor/tsetjmp_raise.nim b/tests/destructor/tsetjmp_raise.nim index b6078ada2..3a9803f39 100644 --- a/tests/destructor/tsetjmp_raise.nim +++ b/tests/destructor/tsetjmp_raise.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "index 2 not in 0 .. 0 [IndexError]" + outputsub: "index 2 not in 0 .. 0 [IndexDefect]" exitcode: 1 cmd: "nim c --gc:arc --exceptions:setjmp $file" """ diff --git a/tests/destructor/tsimpleclosure.nim b/tests/destructor/tsimpleclosure.nim index 4916f4bab..9626dd6f8 100644 --- a/tests/destructor/tsimpleclosure.nim +++ b/tests/destructor/tsimpleclosure.nim @@ -1,11 +1,11 @@ discard """ - cmd: '''nim c -d:nimAllocStats --newruntime $file''' + cmd: '''nim c -d:nimAllocStats --gc:arc $file''' output: '''a b 70 hello hello hello -(allocCount: 4, deallocCount: 4)''' +(allocCount: 3, deallocCount: 3)''' """ import system / ansi_c 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/tv2_raise.nim b/tests/destructor/tv2_raise.nim index 828d0a396..66b0aec30 100644 --- a/tests/destructor/tv2_raise.nim +++ b/tests/destructor/tv2_raise.nim @@ -2,7 +2,7 @@ discard """ valgrind: true cmd: '''nim c -d:nimAllocStats --newruntime $file''' output: '''OK 3 -(allocCount: 8, deallocCount: 3)''' +(allocCount: 7, deallocCount: 4)''' """ import strutils, math 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() diff --git a/tests/destructor/twidgets_unown.nim b/tests/destructor/twidgets_unown.nim index 1d2f26f2a..8653d5c28 100644 --- a/tests/destructor/twidgets_unown.nim +++ b/tests/destructor/twidgets_unown.nim @@ -2,7 +2,7 @@ discard """ cmd: '''nim c -d:nimAllocStats --newruntime $file''' output: '''button clicked! -(allocCount: 9, deallocCount: 9)''' +(allocCount: 6, deallocCount: 6)''' """ import system / ansi_c |