This commit is contained in:
Araq
2019-05-28 21:30:41 +02:00
parent bcccc7dec8
commit 8bb1a6b041
4 changed files with 120 additions and 1 deletions

View File

@@ -1220,6 +1220,21 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
[rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
intLiteral(L+1)])
proc genCaseObjDiscMapping(p: BProc, e: PNode, t: PType, field: PSym; d: var TLoc) =
const ObjDiscMappingProcSlot = -5
var theProc: PSym = nil
for idx, p in items(t.methods):
if idx == ObjDiscMappingProcSlot:
theProc = p
break
if theProc == nil:
theProc = genCaseObjDiscMapping(t, field, e.info, p.module.g.graph)
t.methods.add((ObjDiscMappingProcSlot, theProc))
var call = newNodeIT(nkCall, e.info, getSysType(p.module.g.graph, e.info, tyUInt8))
call.add newSymNode(theProc)
call.add e
expr(p, call, d)
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
var a, tmp: TLoc
var dotExpr = e.sons[0]
@@ -1227,7 +1242,17 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
initLocExpr(p, e.sons[0], a)
getTemp(p, a.t, tmp)
expr(p, e.sons[1], tmp)
genDiscriminantCheck(p, a, tmp, dotExpr.sons[0].typ, dotExpr.sons[1].sym)
let field = dotExpr.sons[1].sym
if optNimV2 in p.config.globalOptions:
let t = dotExpr[0].typ.skipTypes(abstractInst)
var oldVal, newVal: TLoc
genCaseObjDiscMapping(p, e[0], t, field, oldVal)
genCaseObjDiscMapping(p, e[1], t, field, newVal)
lineCg(p, cpsStmts,
"#nimFieldDiscriminantCheckV2($1, $2);$n",
[rdLoc(oldVal), rdLoc(newVal)])
else:
genDiscriminantCheck(p, a, tmp, dotExpr.sons[0].typ, field)
genAssignment(p, a, tmp, {})
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =

View File

@@ -40,3 +40,59 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph): PSym =
n.sons[resultPos] = newSymNode(res)
result.ast = n
incl result.flags, sfFromGeneric
proc searchObjCase(obj: PNode; field: PSym): PNode =
case obj.kind
of nkSym:
result = nil
of nkElse, nkOfBranch:
result = searchObjCase(obj.lastSon, field)
else:
if obj.kind == nkRecCase and obj[0].kind == nkSym and obj[0].sym == field:
result = obj
else:
for x in obj:
result = searchObjCase(x, field)
if result != nil: break
proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph): PSym =
result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), t.owner, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), result, info)
dest.typ = field.typ
let res = newSym(skResult, getIdent(g.cache, "result"), result, info)
res.typ = getSysType(g, info, tyUInt8)
result.typ = newType(tyProc, t.owner)
result.typ.n = newNodeI(nkFormalParams, info)
rawAddSon(result.typ, res.typ)
addSon(result.typ.n, newNodeI(nkEffectList, info))
result.typ.addParam dest
var body = newNodeI(nkStmtList, info)
var caseStmt = newNodeI(nkCaseStmt, info)
caseStmt.add(newSymNode dest)
let subObj = searchObjCase(t.n, field)
doAssert subObj != nil
for i in 1 ..< subObj.len:
let ofBranch = subObj[i]
var newBranch = newNodeI(ofBranch.kind, ofBranch.info)
for j in 0..ofBranch.len-2:
newBranch.add ofBranch[j]
newBranch.add newTree(nkStmtList, newTree(nkFastAsgn, newSymNode(res), newIntNode(nkInt8Lit, i)))
caseStmt.add newBranch
body.add(caseStmt)
var n = newNodeI(nkProcDef, info, bodyPos+2)
for i in 0 ..< n.len: n.sons[i] = newNodeI(nkEmpty, info)
n.sons[namePos] = newSymNode(result)
n.sons[paramsPos] = result.typ.n
n.sons[bodyPos] = body
n.sons[resultPos] = newSymNode(res)
result.ast = n
incl result.flags, sfFromGeneric

View File

@@ -114,3 +114,8 @@ when not defined(nimV2):
if x == nil: return false
x = x.base
return true
when defined(nimV2):
proc nimFieldDiscriminantCheckV2(oldDiscVal, newDiscVal: uint8) {.compilerProc.} =
if oldDiscVal != newDiscVal:
sysFatal(FieldError, "assignment to discriminant changes object branch")

View File

@@ -0,0 +1,33 @@
discard """
cmd: '''nim c --newruntime $file'''
output: '''no crash'''
"""
# bug #11205
type
MyEnum = enum
A, B, C
MyCaseObject = object
case kind: MyEnum
of A: iseq: seq[int]
of B: fseq: seq[float]
of C: str: string
MyCaseObjectB = object # carefully constructed to use the same enum,
# but a different object type!
case kind: MyEnum
of A, C: x: int
of B: fseq: seq[float]
var x = MyCaseObject(kind: A)
x.iseq.add 1
#x.kind = B
#x.fseq.add -3.0
var y = MyCaseObjectB(kind: A)
y.x = 1
y.kind = C
echo "no crash"