From ed126794b6af8b39960a7acc603cee1abc73da4a Mon Sep 17 00:00:00 2001 From: Clyybber Date: Mon, 29 Mar 2021 21:16:11 +0200 Subject: [PATCH] Fix #17412 (#17560) * Fix #17412 * Address review --- compiler/ccgtypes.nim | 28 ++----------------------- compiler/ccgutils.nim | 40 ++++++++++++++++++++++++++++++++++-- compiler/liftdestructors.nim | 11 +++++++++- 3 files changed, 50 insertions(+), 29 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index b0c3aa3b1c..761fd5bf8d 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -256,32 +256,8 @@ proc addAbiCheck(m: BModule, t: PType, name: Rope) = m.s[cfsTypeInfo].addf("NIM_STATIC_ASSERT(sizeof($1) == $2, $3);$n", [name, rope(size), msg2.rope]) # see `testCodegenABICheck` for example error message it generates -proc ccgIntroducedPtr(conf: ConfigRef; s: PSym, retType: PType): bool = - var pt = skipTypes(s.typ, typedescInst) - assert skResult != s.kind - - if tfByRef in pt.flags: return true - elif tfByCopy in pt.flags: return false - case pt.kind - of tyObject: - if s.typ.sym != nil and sfForward in s.typ.sym.flags: - # forwarded objects are *always* passed by pointers for consistency! - result = true - elif (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3): - result = true # requested anyway - elif (tfFinal in pt.flags) and (pt[0] == nil): - result = false # no need, because no subtyping possible - else: - result = true # ordinary objects are always passed by reference, - # otherwise casting doesn't work - of tyTuple: - result = (getSize(conf, pt) > conf.target.floatSize*3) or (optByRef in s.options) - else: - result = false - # first parameter and return type is 'lent T'? --> use pass by pointer - if s.position == 0 and retType != nil and retType.kind == tyLent: - result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or - pt.kind == tySet and mapSetType(conf, pt) == ctArray) +from ccgutils import ccgIntroducedPtr +export ccgIntroducedPtr proc fillResult(conf: ConfigRef; param: PNode) = fillLoc(param.sym.loc, locParam, param, ~"Result", diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index f2a8c1e360..06b75a20fa 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -10,8 +10,8 @@ # This module declares some helpers for the C code generator. import - ast, hashes, strutils, msgs, wordrecg, - platform, trees, options + ast, types, hashes, strutils, msgs, wordrecg, + platform, trees, options, cgendata proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode = case n.kind @@ -106,3 +106,39 @@ proc mangle*(name: string): string = requiresUnderscore = true if requiresUnderscore: result.add "_" + +proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind = + case int(getSize(conf, typ)) + of 1: result = ctInt8 + of 2: result = ctInt16 + of 4: result = ctInt32 + of 8: result = ctInt64 + else: result = ctArray + +proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool = + var pt = skipTypes(s.typ, typedescInst) + assert skResult != s.kind + + if tfByRef in pt.flags: return true + elif tfByCopy in pt.flags: return false + case pt.kind + of tyObject: + if s.typ.sym != nil and sfForward in s.typ.sym.flags: + # forwarded objects are *always* passed by pointers for consistency! + result = true + elif (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3): + result = true # requested anyway + elif (tfFinal in pt.flags) and (pt[0] == nil): + result = false # no need, because no subtyping possible + else: + result = true # ordinary objects are always passed by reference, + # otherwise casting doesn't work + of tyTuple: + result = (getSize(conf, pt) > conf.target.floatSize*3) or (optByRef in s.options) + else: + result = false + # first parameter and return type is 'lent T'? --> use pass by pointer + if s.position == 0 and retType != nil and retType.kind == tyLent: + result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or + pt.kind == tySet and mapSetType(conf, pt) == ctArray) + diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 980e77e4be..bb24fed341 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -11,7 +11,7 @@ ## (``=sink``, ``=``, ``=destroy``, ``=deepCopy``). import modulegraphs, lineinfos, idents, ast, renderer, semdata, - sighashes, lowerings, options, types, msgs, magicsys, tables + sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils from trees import isCaseObj @@ -230,6 +230,15 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) = # for every field (dependent on dest.kind): # `=` dest.field, src.field # =destroy(blob) + var dummy = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId c.idgen, c.fn, c.info) + dummy.typ = y.typ + if ccgIntroducedPtr(c.g.config, dummy, y.typ): + # Because of potential aliasing when the src param is passed by ref, we need to check for equality here, + # because the wasMoved(dest) call would zero out src, if dest aliases src. + var cond = newTree(nkCall, newSymNode(c.g.getSysMagic(c.info, "==", mEqRef)), + newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x), newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y)) + cond.typ = getSysType(c.g, x.info, tyBool) + body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info))) var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId c.idgen, c.fn, c.info) temp.typ = x.typ incl(temp.flags, sfFromGeneric)