diff options
-rw-r--r-- | compiler/semcall.nim | 2 | ||||
-rw-r--r-- | compiler/semexprs.nim | 1 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 10 | ||||
-rw-r--r-- | tests/converter/tconverter_unique_ptr.nim | 107 |
4 files changed, 118 insertions, 2 deletions
diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 4e2a45209..7e0ea5490 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -138,6 +138,7 @@ proc effectProblem(f, a: PType; result: var string) = proc renderNotLValue(n: PNode): string = result = $n + let n = if n.kind == nkHiddenDeref: n[0] else: n if n.kind == nkHiddenCallConv and n.len > 1: result = $n[0] & "(" & result & ")" elif n.kind in {nkHiddenStdConv, nkHiddenSubConv} and n.len == 2: @@ -394,6 +395,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode, args]) proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) = + let a = if a.kind == nkHiddenDeref: a[0] else: a if a.kind == nkHiddenCallConv and a.sons[0].kind == nkSym: let s = a.sons[0].sym if s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 0e4f0575f..3d77ae524 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -640,6 +640,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = return for i in countup(1, sonsLen(n) - 1): + let n = if n.kind == nkHiddenDeref: n[0] else: n if n.sons[i].kind == nkHiddenCallConv: # we need to recurse explicitly here as converters can create nested # calls and then they wouldn't be analysed otherwise diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index d5b2bb8b4..4adf0bed3 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -13,7 +13,7 @@ import intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees, - linter, lineinfos, modulegraphs + linter, lineinfos, lowerings, modulegraphs when (defined(booting) or defined(nimsuggest)) and not defined(leanCompiler): import docgen @@ -1855,8 +1855,14 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, else: param = copyTree(arg) addSon(result, param) + + if dest.kind in {tyVar, tyLent}: + dest.flags.incl tfVarIsPtr + result = newDeref(result) + inc(m.convMatches) - m.genericConverter = srca == isGeneric or destIsGeneric + if m.genericConverter == false: + m.genericConverter = srca == isGeneric or destIsGeneric return result proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, diff --git a/tests/converter/tconverter_unique_ptr.nim b/tests/converter/tconverter_unique_ptr.nim new file mode 100644 index 000000000..15ec609a3 --- /dev/null +++ b/tests/converter/tconverter_unique_ptr.nim @@ -0,0 +1,107 @@ + +discard """ + file: "tconverter_unique_ptr.nim" + targets: "c cpp" + output: '''5 +2.0 5 +''' +""" + +## Bugs 9698 and 9699 + +type + UniquePtr*[T] = object + ## non copyable pointer to object T, exclusive ownership of the object is assumed + val: ptr T + + MyLen* = distinct int + + MySeq* = object + ## Vectorized matrix + len: MyLen # scalar size + data: ptr UncheckedArray[float] + +proc `$`(x: MyLen): string {.borrow.} + +proc `=destroy`*(m: var MySeq) {.inline.} = + if m.data != nil: + deallocShared(m.data) + m.data = nil + +proc `=`*(m: var MySeq, m2: MySeq) = + if m.data == m2.data: return + if m.data != nil: + `=destroy`(m) + + m.len = m2.len + let bytes = m.len.int * sizeof(float) + if bytes > 0: + m.data = cast[ptr UncheckedArray[float]](allocShared(bytes)) + copyMem(m.data, m2.data, bytes) + +proc `=sink`*(m: var MySeq, m2: MySeq) {.inline.} = + if m.data != m2.data: + if m.data != nil: + `=destroy`(m) + m.len = m2.len + m.data = m2.data + +proc len*(m: MySeq): MyLen {.inline.} = m.len + +proc lenx*(m: var MySeq): MyLen {.inline.} = m.len + + +proc `[]`*(m: MySeq; i: MyLen): float {.inline.} = + m.data[i.int] + +proc `[]=`*(m: var MySeq; i: MyLen, val: float) {.inline.} = + m.data[i.int] = val + +proc setTo(s: var MySeq, val: float) = + for i in 0..<s.len.int: + s.data[i] = val + +proc newMySeq*(size: int, initial_value = 0.0): MySeq = + result.len = size.MyLen + if size > 0: + result.data = cast[ptr UncheckedArray[float]](createShared(float, size)) + + result.setTo(initial_value) + +converter literalToLen*(x: int{lit}): MyLen = + x.MyLen + + +#------------------------------------------------------------- +# Unique pointer implementation +#------------------------------------------------------------- + +proc `=destroy`*[T](p: var UniquePtr[T]) = + if p.val != nil: + `=destroy`(p.val[]) + dealloc(p.val) + p.val = nil + +proc `=`*[T](dest: var UniquePtr[T], src: UniquePtr[T]) {.error.} + +proc `=sink`*[T](dest: var UniquePtr[T], src: UniquePtr[T]) {.inline.} = + if dest.val != nil and dest.val != src.val: + `=destroy`(dest) + dest.val = src.val + +proc newUniquePtr*[T](val: sink T): UniquePtr[T] = + result.val = cast[type(result.val)](alloc(sizeof(result.val[]))) + reset(result.val[]) + result.val[] = val + +converter convertPtrToObj*[T](p: UniquePtr[T]): var T = + result = p.val[] + + +var pu = newUniquePtr(newMySeq(5, 1.0)) +echo pu.len + +pu[0] = 2.0 +echo pu[0], " ", pu.lenx + + |