diff options
author | Saem Ghani <saemghani+github@gmail.com> | 2021-03-02 01:32:43 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-02 10:32:43 +0100 |
commit | ab780f66ef67ea0333278d75e4af064bcae71c57 (patch) | |
tree | e7f778e6a92d12803c7cb8c68e432d0eecdd045b | |
parent | 33833968c46dd3a5dc8c379abdb7021b0d304b7f (diff) | |
download | Nim-ab780f66ef67ea0333278d75e4af064bcae71c57.tar.gz |
fixes #17198, DFA failure on large case stmts (#17210)
This alters the DFA control flow graph generation for case statments. Gotos are now generated as a chained link, this ensures that evaluation of variant branches collapses as early as possible, without hitting the 2k call limit.
-rw-r--r-- | compiler/dfa.nim | 11 | ||||
-rw-r--r-- | tests/destructor/t17198.nim | 32 |
2 files changed, 40 insertions, 3 deletions
diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 517d13831..c7a9d4694 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -455,6 +455,10 @@ proc genCase(c: var Con; n: PNode) = let isExhaustive = skipTypes(n[0].typ, abstractVarRange-{tyTypeDesc}).kind notin {tyFloat..tyFloat128, tyString} + # we generate endings as a set of chained gotos, this is a bit awkward but it + # ensures when recursively traversing the CFG for various analysis, we don't + # artificially extended the life of each branch (for the purposes of DFA) + # beyond the minimum amount. var endings: seq[TPosition] = @[] c.gen(n[0]) for i in 1..<n.len: @@ -462,13 +466,14 @@ proc genCase(c: var Con; n: PNode) = if it.len == 1 or (i == n.len-1 and isExhaustive): # treat the last branch as 'else' if this is an exhaustive case statement. c.gen(it.lastSon) + if endings.len != 0: + c.patch(endings[^1]) else: forkT(it.lastSon): c.gen(it.lastSon) + if endings.len != 0: + c.patch(endings[^1]) endings.add c.gotoI(it.lastSon) - for i in countdown(endings.high, 0): - let endPos = endings[i] - c.patch(endPos) proc genBlock(c: var Con; n: PNode) = withBlock(n[0].sym): diff --git a/tests/destructor/t17198.nim b/tests/destructor/t17198.nim new file mode 100644 index 000000000..098db8245 --- /dev/null +++ b/tests/destructor/t17198.nim @@ -0,0 +1,32 @@ +discard """ + cmd: '''nim c --gc:arc $file''' + output: ''' +other +''' +""" + +import std/macros + +macro bigCaseStmt(arg: untyped): untyped = + result = nnkCaseStmt.newTree(arg) + + # try to change 2000 to a bigger value if it doesn't crash + for x in 0 ..< 2000: + result.add nnkOfBranch.newTree(newStrLitNode($x), newStrLitNode($x)) + + result.add nnkElse.newTree(newStrLitNode("other")) + +macro bigIfElseExpr(): untyped = + result = nnkIfExpr.newTree() + + for x in 0 ..< 1000: + result.add nnkElifExpr.newTree(newLit(false), newStrLitNode($x)) + + result.add nnkElseExpr.newTree(newStrLitNode("other")) + +proc test(arg: string): string = + echo bigIfElseExpr() + + result = bigCaseStmt(arg) + +discard test("test") |