DFA: implement exception handling properly

This commit is contained in:
Andreas Rumpf 2018-10-14 13:19:33 +02:00
commit b39302b0d2
3 changed files with 55 additions and 16 deletions

View file

@ -216,6 +216,7 @@ proc isLastRead(n: PNode; c: var Con): bool =
let s = n.sym let s = n.sym
var pcs: seq[int] = @[instr+1] var pcs: seq[int] = @[instr+1]
var takenGotos: IntSet var takenGotos: IntSet
var takenForks = initIntSet()
while pcs.len > 0: while pcs.len > 0:
var pc = pcs.pop var pc = pcs.pop
@ -251,7 +252,7 @@ proc isLastRead(n: PNode; c: var Con): bool =
inc pc inc pc
of fork: of fork:
# we follow the next instruction but push the dest onto our "work" stack: # we follow the next instruction but push the dest onto our "work" stack:
if not takenGotos.containsOrIncl(pc): if not takenForks.containsOrIncl(pc):
pcs.add pc + c.g[pc].dest pcs.add pc + c.g[pc].dest
inc pc inc pc
#echo c.graph.config $ n.info, " last read here!" #echo c.graph.config $ n.info, " last read here!"

View file

@ -53,8 +53,9 @@ type
Con = object Con = object
code: ControlFlowGraph code: ControlFlowGraph
inCall: int inCall, inTryStmt: int
blocks: seq[TBlock] blocks: seq[TBlock]
tryStmtFixups: seq[TPosition]
proc debugInfo(info: TLineInfo): string = proc debugInfo(info: TLineInfo): string =
result = $info.line #info.toFilename & ":" & $info.line result = $info.line #info.toFilename & ":" & $info.line
@ -225,8 +226,17 @@ proc genCase(c: var Con; n: PNode) =
proc genTry(c: var Con; n: PNode) = proc genTry(c: var Con; n: PNode) =
var endings: seq[TPosition] = @[] var endings: seq[TPosition] = @[]
inc c.inTryStmt
var newFixups: seq[TPosition]
swap(newFixups, c.tryStmtFixups)
let elsePos = c.forkI(n) let elsePos = c.forkI(n)
c.gen(n.sons[0]) c.gen(n.sons[0])
dec c.inTryStmt
for f in newFixups:
c.patch(f)
swap(newFixups, c.tryStmtFixups)
c.patch(elsePos) c.patch(elsePos)
for i in 1 ..< n.len: for i in 1 ..< n.len:
let it = n.sons[i] let it = n.sons[i]
@ -244,7 +254,10 @@ proc genTry(c: var Con; n: PNode) =
proc genRaise(c: var Con; n: PNode) = proc genRaise(c: var Con; n: PNode) =
gen(c, n.sons[0]) gen(c, n.sons[0])
c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len) if c.inTryStmt > 0:
c.tryStmtFixups.add c.gotoI(n)
else:
c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len)
proc genReturn(c: var Con; n: PNode) = proc genReturn(c: var Con; n: PNode) =
if n.sons[0].kind != nkEmpty: gen(c, n.sons[0]) if n.sons[0].kind != nkEmpty: gen(c, n.sons[0])
@ -275,6 +288,9 @@ proc genCall(c: var Con; n: PNode) =
gen(c, n[i]) gen(c, n[i])
if t != nil and i < t.len and t.sons[i].kind == tyVar: if t != nil and i < t.len and t.sons[i].kind == tyVar:
genDef(c, n[i]) genDef(c, n[i])
# every call can potentially raise:
if c.inTryStmt > 0:
c.tryStmtFixups.add c.forkI(n)
dec c.inCall dec c.inCall
proc genMagic(c: var Con; n: PNode; m: TMagic) = proc genMagic(c: var Con; n: PNode; m: TMagic) =
@ -340,6 +356,8 @@ proc gen(c: var Con; n: PNode) =
gen(c, n.sons[1]) gen(c, n.sons[1])
of nkObjDownConv, nkStringToCString, nkCStringToString: gen(c, n.sons[0]) of nkObjDownConv, nkStringToCString, nkCStringToString: gen(c, n.sons[0])
of nkVarSection, nkLetSection: genVarSection(c, n) of nkVarSection, nkLetSection: genVarSection(c, n)
of nkDefer:
doAssert false, "dfa construction pass requires the elimination of 'defer'"
else: discard else: discard
proc dfa(code: seq[Instr]; conf: ConfigRef) = proc dfa(code: seq[Instr]; conf: ConfigRef) =

View file

@ -1,6 +1,12 @@
discard """ discard """
errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'" errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
line: 44
cmd: "nim check --hint[Performance]:off $file"
nimout: '''
tprevent_assign2.nim(53, 31) Error: '=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'; another read is done here: tprevent_assign2.nim(52, 13)
tprevent_assign2.nim(55, 31) Error: '=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'; another read is done here: tprevent_assign2.nim(52, 13)
tprevent_assign2.nim(66, 29) Error: '=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'; another read is done here: tprevent_assign2.nim(68, 9)
'''
""" """
type type
@ -19,18 +25,21 @@ proc take2(a, b: sink Foo) =
proc allowThis() = proc allowThis() =
var otherTree: Foo var otherTree: Foo
for i in 0..3: try:
while true: for i in 0..3:
#if i == 0: while true:
otherTree = createTree(44) #if i == 0:
case i otherTree = createTree(44)
of 0: case i
echo otherTree of 0:
take2(createTree(34), otherTree) echo otherTree
of 1: take2(createTree(34), otherTree)
take2(createTree(34), otherTree) of 1:
else: take2(createTree(34), otherTree)
discard else:
discard
finally:
discard
proc preventThis() = proc preventThis() =
var otherTree: Foo var otherTree: Foo
@ -46,3 +55,14 @@ proc preventThis() =
take2(createTree(34), otherTree) take2(createTree(34), otherTree)
else: else:
discard discard
proc preventThis2() =
var otherTree: Foo
try:
try:
otherTree = createTree(44)
echo otherTree
finally:
take2(createTree(34), otherTree)
finally:
echo otherTree