Field checks for everybody (#8957)
* Field checks for JS backend * Clean nkCall nodes with no arguments Generating a nkEmpty in place of no arguments makes no sense form the AST point of view and also trips up the VM codegen. * Field checks for VM backend * Test case for #6612 This patchset fixes #6612 * Add test case for LHS double evaluation * Prevent LHS double-eval for JS backend * Prevent double evaluation in VM backend
This commit is contained in:
parent
a3fb0a769c
commit
ee14ace5d3
10 changed files with 223 additions and 43 deletions
|
|
@ -562,6 +562,8 @@ proc genIndex(c: PCtx; n: PNode; arr: PType): TRegister =
|
|||
else:
|
||||
result = c.genx(n)
|
||||
|
||||
proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags)
|
||||
|
||||
proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
|
||||
case le.kind
|
||||
of nkBracketExpr:
|
||||
|
|
@ -570,12 +572,16 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
|
|||
c.gABC(le, opcWrArr, dest, idx, value)
|
||||
c.freeTemp(dest)
|
||||
c.freeTemp(idx)
|
||||
of nkDotExpr, nkCheckedFieldExpr:
|
||||
# XXX field checks here
|
||||
let left = if le.kind == nkDotExpr: le else: le.sons[0]
|
||||
let dest = c.genx(left.sons[0], {gfNode})
|
||||
let idx = genField(c, left.sons[1])
|
||||
c.gABC(left, opcWrObj, dest, idx, value)
|
||||
of nkCheckedFieldExpr:
|
||||
var objR: TDest = -1
|
||||
genCheckedObjAccessAux(c, le, objR, {gfNode})
|
||||
let idx = genField(c, le[0].sons[1])
|
||||
c.gABC(le[0], opcWrObj, objR, idx, value)
|
||||
c.freeTemp(objR)
|
||||
of nkDotExpr:
|
||||
let dest = c.genx(le.sons[0], {gfNode})
|
||||
let idx = genField(c, le.sons[1])
|
||||
c.gABC(le, opcWrObj, dest, idx, value)
|
||||
c.freeTemp(dest)
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
let dest = c.genx(le.sons[0], {gfNode})
|
||||
|
|
@ -1419,13 +1425,19 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
|||
else:
|
||||
c.preventFalseAlias(le, opcWrArr, dest, idx, tmp)
|
||||
c.freeTemp(tmp)
|
||||
of nkDotExpr, nkCheckedFieldExpr:
|
||||
# XXX field checks here
|
||||
let left = if le.kind == nkDotExpr: le else: le.sons[0]
|
||||
let dest = c.genx(left.sons[0], {gfNode})
|
||||
let idx = genField(c, left.sons[1])
|
||||
of nkCheckedFieldExpr:
|
||||
var objR: TDest = -1
|
||||
genCheckedObjAccessAux(c, le, objR, {gfNode})
|
||||
let idx = genField(c, le[0].sons[1])
|
||||
let tmp = c.genx(ri)
|
||||
c.preventFalseAlias(left, opcWrObj, dest, idx, tmp)
|
||||
c.preventFalseAlias(le[0], opcWrObj, objR, idx, tmp)
|
||||
c.freeTemp(tmp)
|
||||
c.freeTemp(objR)
|
||||
of nkDotExpr:
|
||||
let dest = c.genx(le.sons[0], {gfNode})
|
||||
let idx = genField(c, le.sons[1])
|
||||
let tmp = c.genx(ri)
|
||||
c.preventFalseAlias(le, opcWrObj, dest, idx, tmp)
|
||||
c.freeTemp(tmp)
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
let dest = c.genx(le.sons[0], {gfNode})
|
||||
|
|
@ -1561,9 +1573,59 @@ proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
|||
c.gABC(n, opcLdObj, dest, a, b)
|
||||
c.freeTemp(a)
|
||||
|
||||
proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
internalAssert c.config, n.kind == nkCheckedFieldExpr
|
||||
# nkDotExpr to access the requested field
|
||||
let accessExpr = n[0]
|
||||
# nkCall to check if the discriminant is valid
|
||||
var checkExpr = n[1]
|
||||
|
||||
let negCheck = checkExpr[0].sym.magic == mNot
|
||||
if negCheck:
|
||||
checkExpr = checkExpr[^1]
|
||||
|
||||
# Discriminant symbol
|
||||
let disc = checkExpr[2]
|
||||
internalAssert c.config, disc.sym.kind == skField
|
||||
|
||||
# Load the object in `dest`
|
||||
c.gen(accessExpr[0], dest, flags)
|
||||
# Load the discriminant
|
||||
var discVal = c.getTemp(disc.typ)
|
||||
c.gABC(n, opcLdObj, discVal, dest, genField(c, disc))
|
||||
# Check if its value is contained in the supplied set
|
||||
let setLit = c.genx(checkExpr[1])
|
||||
var rs = c.getTemp(getSysType(c.graph, n.info, tyBool))
|
||||
c.gABC(n, opcContainsSet, rs, setLit, discVal)
|
||||
c.freeTemp(setLit)
|
||||
# If the check fails let the user know
|
||||
let L1 = c.xjmp(n, if negCheck: opcFJmp else: opcTJmp, rs)
|
||||
c.freeTemp(rs)
|
||||
# Not ideal but will do for the moment
|
||||
c.gABC(n, opcQuit)
|
||||
c.patch(L1)
|
||||
|
||||
proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
# XXX implement field checks!
|
||||
genObjAccess(c, n.sons[0], dest, flags)
|
||||
var objR: TDest = -1
|
||||
genCheckedObjAccessAux(c, n, objR, flags)
|
||||
|
||||
let accessExpr = n[0]
|
||||
# Field symbol
|
||||
var field = accessExpr[1]
|
||||
internalAssert c.config, field.sym.kind == skField
|
||||
|
||||
# Load the content now
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
let fieldPos = genField(c, field)
|
||||
if needsRegLoad():
|
||||
var cc = c.getTemp(accessExpr.typ)
|
||||
c.gABC(n, opcLdObj, cc, objR, fieldPos)
|
||||
c.gABC(n, opcNodeToReg, dest, cc)
|
||||
c.freeTemp(cc)
|
||||
else:
|
||||
c.gABC(n, opcLdObj, dest, objR, fieldPos)
|
||||
|
||||
c.freeTemp(objR)
|
||||
|
||||
proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
let arrayType = n.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue