FIR CFA: remove redundant "uncaught exception path" edges

These are not real, and in fact tricked the compiler into thinking some
blocks that do not terminate do somehow terminate.
This commit is contained in:
pyos
2022-11-27 23:03:00 +01:00
committed by Dmitriy Novozhilov
parent fa0ea1504e
commit ef2fa01a8d
23 changed files with 277 additions and 88 deletions
@@ -101,7 +101,6 @@ digraph initializationInTry_kt {
26 -> {27};
27 -> {28};
28 -> {29};
28 -> {33} [label="onUncaughtException"];
29 -> {30};
30 -> {31};
31 -> {32};
@@ -168,7 +167,6 @@ digraph initializationInTry_kt {
48 -> {49};
49 -> {50};
50 -> {51};
50 -> {55} [label="onUncaughtException"];
51 -> {52};
52 -> {53};
53 -> {54};
@@ -148,7 +148,6 @@ digraph complex_kt {
25 -> {26};
26 -> {27 36};
27 -> {28};
27 -> {52} [label="onUncaughtException"];
28 -> {29};
29 -> {30};
30 -> {31};
@@ -195,12 +195,11 @@ digraph flowFromInplaceLambda_kt {
97 [label="Stub" style="filled" fillcolor=gray];
98 [label="Exit block" style="filled" fillcolor=gray];
}
99 [label="Exit function materialize" style="filled" fillcolor=red];
99 [label="Exit function materialize" style="filled" fillcolor=red style="filled" fillcolor=gray];
}
91 -> {92};
92 -> {93};
93 -> {94};
94 -> {99} [label="onUncaughtException"];
94 -> {95} [style=dotted];
95 -> {96} [style=dotted];
96 -> {97 99} [style=dotted];
@@ -66,26 +66,25 @@ digraph initBlock_kt {
23 [label="Variable declaration: lval y: R|kotlin/Int|" style="filled" fillcolor=gray];
24 [label="Exit block" style="filled" fillcolor=gray];
}
25 [label="Exit init block" style="filled" fillcolor=red];
25 [label="Exit init block" style="filled" fillcolor=red style="filled" fillcolor=gray];
}
15 -> {16};
16 -> {17};
17 -> {18};
18 -> {19};
19 -> {20};
20 -> {25} [label="onUncaughtException"];
20 -> {21} [style=dotted];
21 -> {22} [style=dotted];
22 -> {23} [style=dotted];
23 -> {24} [style=dotted];
24 -> {25} [style=dotted];
25 -> {28} [color=green];
25 -> {28} [style=dotted];
subgraph cluster_7 {
color=red
26 [label="Enter class Bar" style="filled" fillcolor=red];
27 [label="Part of class initialization"];
28 [label="Exit class Bar" style="filled" fillcolor=red];
28 [label="Exit class Bar" style="filled" fillcolor=red style="filled" fillcolor=gray];
}
26 -> {27} [color=green];
27 -> {15} [color=green];
@@ -16,12 +16,11 @@ digraph inplaceLambdaInControlFlowExpressions_kt {
6 [label="Stub" style="filled" fillcolor=gray];
7 [label="Exit block" style="filled" fillcolor=gray];
}
8 [label="Exit function materialize" style="filled" fillcolor=red];
8 [label="Exit function materialize" style="filled" fillcolor=red style="filled" fillcolor=gray];
}
0 -> {1};
1 -> {2};
2 -> {3};
3 -> {8} [label="onUncaughtException"];
3 -> {4} [style=dotted];
4 -> {5} [style=dotted];
5 -> {6 8} [style=dotted];
@@ -182,7 +181,6 @@ digraph inplaceLambdaInControlFlowExpressions_kt {
46 -> {47};
47 -> {48 54};
48 -> {49};
48 -> {57} [label="onUncaughtException"];
49 -> {50};
50 -> {51};
51 -> {52};
@@ -75,7 +75,6 @@ digraph jumps_kt {
16 -> {17};
17 -> {18};
18 -> {19};
19 -> {31} [label="onUncaughtException"];
19 -> {20} [style=dotted];
20 -> {21} [style=dotted];
21 -> {22} [style=dotted];
@@ -59,11 +59,10 @@ digraph lambdaReturningObject_kt {
18 [label="Stub" style="filled" fillcolor=gray];
19 [label="Exit block" style="filled" fillcolor=gray];
}
20 [label="Exit function MyOut" style="filled" fillcolor=red];
20 [label="Exit function MyOut" style="filled" fillcolor=red style="filled" fillcolor=gray];
}
13 -> {14};
14 -> {15};
15 -> {20} [label="onUncaughtException"];
15 -> {16} [style=dotted];
16 -> {17} [style=dotted];
17 -> {18 20} [style=dotted];
@@ -329,7 +329,6 @@ digraph postponedLambdaInReturn_kt {
101 -> {102} [style=dotted];
102 -> {103 108} [style=dotted];
103 -> {104};
103 -> {84} [label="onUncaughtException"];
104 -> {105};
105 -> {106};
106 -> {107};
@@ -339,7 +338,6 @@ digraph postponedLambdaInReturn_kt {
110 -> {88} [color=green style=dashed];
111 -> {112} [style=dotted];
112 -> {113} [style=dotted];
113 -> {84} [style=dotted label="onUncaughtException"];
113 -> {114} [style=dotted];
114 -> {115} [style=dotted];
115 -> {116} [style=dotted];
@@ -91,7 +91,7 @@ digraph propertiesAndInitBlocks_kt {
43 [label="Stub" style="filled" fillcolor=gray];
44 [label="Exit block" style="filled" fillcolor=gray];
}
45 [label="Exit function foo" style="filled" fillcolor=red];
45 [label="Exit function foo" style="filled" fillcolor=red style="filled" fillcolor=gray];
}
35 -> {36};
36 -> {37};
@@ -100,7 +100,6 @@ digraph propertiesAndInitBlocks_kt {
39 -> {40};
40 -> {41};
41 -> {42};
42 -> {45} [label="onUncaughtException"];
42 -> {43} [style=dotted];
43 -> {44} [style=dotted];
44 -> {45} [style=dotted];
@@ -126,17 +125,16 @@ digraph propertiesAndInitBlocks_kt {
54 [label="Const: Int(1)" style="filled" fillcolor=gray];
55 [label="Exit block" style="filled" fillcolor=gray];
}
56 [label="Exit init block" style="filled" fillcolor=red];
56 [label="Exit init block" style="filled" fillcolor=red style="filled" fillcolor=gray];
}
49 -> {50};
50 -> {51};
51 -> {52};
52 -> {56} [label="onUncaughtException"];
52 -> {53} [style=dotted];
53 -> {54} [style=dotted];
54 -> {55} [style=dotted];
55 -> {56} [style=dotted];
56 -> {34} [color=green];
56 -> {34} [style=dotted];
subgraph cluster_13 {
color=red
@@ -153,7 +151,7 @@ digraph propertiesAndInitBlocks_kt {
color=blue
62 [label="Enter class GetterLocalClass" style="filled" fillcolor=red];
63 [label="Part of class initialization"];
64 [label="Exit class GetterLocalClass" style="filled" fillcolor=red];
64 [label="Exit class GetterLocalClass" style="filled" fillcolor=red style="filled" fillcolor=gray];
}
57 -> {58};
58 -> {59};
@@ -187,16 +185,15 @@ digraph propertiesAndInitBlocks_kt {
72 [label="Stub" style="filled" fillcolor=gray];
73 [label="Exit block" style="filled" fillcolor=gray];
}
74 [label="Exit init block" style="filled" fillcolor=red];
74 [label="Exit init block" style="filled" fillcolor=red style="filled" fillcolor=gray];
}
68 -> {69};
69 -> {70};
70 -> {71};
71 -> {74} [label="onUncaughtException"];
71 -> {72} [style=dotted];
72 -> {73} [style=dotted];
73 -> {74} [style=dotted];
74 -> {64} [color=green];
74 -> {64} [style=dotted];
subgraph cluster_19 {
color=red
@@ -220,7 +217,7 @@ digraph propertiesAndInitBlocks_kt {
color=blue
32 [label="Enter class InitializerLocalClass" style="filled" fillcolor=red];
33 [label="Part of class initialization"];
34 [label="Exit class InitializerLocalClass" style="filled" fillcolor=red];
34 [label="Exit class InitializerLocalClass" style="filled" fillcolor=red style="filled" fillcolor=gray];
}
77 [label="Postponed exit from lambda"];
78 [label="Function call: R|/run|(...)" style="filled" fillcolor=yellow];
@@ -239,7 +236,6 @@ digraph propertiesAndInitBlocks_kt {
26 -> {32 46} [color=green];
26 -> {32 46} [style=dashed];
27 -> {28};
28 -> {79} [label="onUncaughtException"];
28 -> {29} [style=dotted];
29 -> {30} [style=dotted];
30 -> {31} [style=dotted];
@@ -313,7 +309,6 @@ digraph propertiesAndInitBlocks_kt {
95 -> {96};
96 -> {97};
97 -> {98};
97 -> {99} [label="onUncaughtException"];
98 -> {99};
}
@@ -196,7 +196,6 @@ digraph returnValuesFromLambda_kt {
55 -> {56 57} [style=dotted];
55 -> {62} [style=dashed];
56 -> {57} [style=dotted];
57 -> {61} [style=dotted label="onUncaughtException"];
57 -> {58} [style=dotted];
58 -> {59} [style=dotted];
59 -> {60} [style=dotted];
@@ -66,7 +66,6 @@ digraph tryCatch_kt {
7 -> {8};
8 -> {9 16 23};
9 -> {10};
9 -> {25} [label="onUncaughtException"];
10 -> {11};
11 -> {12};
12 -> {13};
@@ -74,7 +73,6 @@ digraph tryCatch_kt {
14 -> {15};
15 -> {23};
16 -> {17};
16 -> {25} [label="onUncaughtException"];
17 -> {18};
18 -> {19};
19 -> {20};
@@ -132,7 +130,6 @@ digraph tryCatch_kt {
32 -> {33};
33 -> {34 40};
34 -> {35};
34 -> {43} [label="onUncaughtException"];
35 -> {36};
36 -> {37};
37 -> {38};
@@ -307,7 +304,6 @@ digraph tryCatch_kt {
82 -> {83};
83 -> {84 91 103};
84 -> {85};
84 -> {99} [label="onUncaughtException"];
85 -> {86};
86 -> {87};
87 -> {47} [color=green style=dashed];
@@ -316,7 +312,6 @@ digraph tryCatch_kt {
89 -> {90} [style=dotted];
90 -> {103} [style=dotted];
91 -> {92};
91 -> {99} [label="onUncaughtException"];
92 -> {93};
93 -> {94};
94 -> {95};
@@ -83,7 +83,7 @@ digraph variableInitializedInTryBlock_kt {
23 -> {24};
24 -> {25};
25 -> {26};
25 -> {30} [label="onUncaughtException"];
25 -> {30} [label="return@/test"];
26 -> {27};
27 -> {28};
28 -> {29};
@@ -52,7 +52,6 @@ digraph jumpFromRhsOfOperator_kt {
10 -> {11 15};
11 -> {12};
12 -> {13};
13 -> {20} [label="onUncaughtException"];
13 -> {14} [style=dotted];
14 -> {15} [style=dotted];
15 -> {16};
@@ -96,7 +95,6 @@ digraph jumpFromRhsOfOperator_kt {
27 -> {28 32};
28 -> {29};
29 -> {30};
30 -> {37} [label="onUncaughtException"];
30 -> {31} [style=dotted];
31 -> {32} [style=dotted];
32 -> {33};
@@ -163,7 +161,6 @@ digraph jumpFromRhsOfOperator_kt {
46 -> {47 51};
47 -> {48};
48 -> {49};
49 -> {66} [label="onUncaughtException"];
49 -> {50} [style=dotted];
50 -> {51} [style=dotted];
51 -> {52};
@@ -240,7 +237,6 @@ digraph jumpFromRhsOfOperator_kt {
75 -> {76 80};
76 -> {77};
77 -> {78};
78 -> {95} [label="onUncaughtException"];
78 -> {79} [style=dotted];
79 -> {80} [style=dotted];
80 -> {81};
@@ -294,7 +290,6 @@ digraph jumpFromRhsOfOperator_kt {
102 -> {103 107};
103 -> {104};
104 -> {105};
105 -> {112} [label="onUncaughtException"];
105 -> {106} [style=dotted];
106 -> {107} [style=dotted];
107 -> {108};
@@ -338,7 +333,6 @@ digraph jumpFromRhsOfOperator_kt {
119 -> {120 124};
120 -> {121};
121 -> {122};
122 -> {129} [label="onUncaughtException"];
122 -> {123} [style=dotted];
123 -> {124} [style=dotted];
124 -> {125};
@@ -405,7 +399,6 @@ digraph jumpFromRhsOfOperator_kt {
138 -> {139 143};
139 -> {140};
140 -> {141};
141 -> {158} [label="onUncaughtException"];
141 -> {142} [style=dotted];
142 -> {143} [style=dotted];
143 -> {144};
@@ -482,7 +475,6 @@ digraph jumpFromRhsOfOperator_kt {
167 -> {168 172};
168 -> {169};
169 -> {170};
170 -> {187} [label="onUncaughtException"];
170 -> {171} [style=dotted];
171 -> {172} [style=dotted];
172 -> {173};
@@ -871,7 +871,6 @@ digraph boundSmartcastsInBranches_kt {
309 -> {310};
310 -> {311};
311 -> {312};
312 -> {341} [label="onUncaughtException"];
312 -> {313} [style=dotted];
313 -> {314} [style=dotted];
314 -> {315} [style=dotted];
@@ -1207,7 +1206,6 @@ digraph boundSmartcastsInBranches_kt {
446 -> {447};
447 -> {448};
448 -> {449};
449 -> {479} [label="onUncaughtException"];
449 -> {450} [style=dotted];
450 -> {451} [style=dotted];
451 -> {452} [style=dotted];
@@ -295,7 +295,6 @@ digraph safeCalls_kt {
97 -> {98 99} [style=dotted];
97 -> {112} [style=dashed];
98 -> {99} [style=dotted];
99 -> {111} [style=dotted label="onUncaughtException"];
99 -> {100} [style=dotted];
100 -> {101 106} [style=dotted];
101 -> {102} [style=dotted];
@@ -36,11 +36,10 @@ digraph smartCastInInit_kt {
11 [label="Stub" style="filled" fillcolor=gray];
12 [label="Exit block" style="filled" fillcolor=gray];
}
13 [label="Exit function s" style="filled" fillcolor=red];
13 [label="Exit function s" style="filled" fillcolor=red style="filled" fillcolor=gray];
}
6 -> {7};
7 -> {8};
8 -> {13} [label="onUncaughtException"];
8 -> {9} [style=dotted];
9 -> {10} [style=dotted];
10 -> {11 13} [style=dotted];
@@ -16,12 +16,11 @@ digraph smartcastToNothing_kt {
6 [label="Stub" style="filled" fillcolor=gray];
7 [label="Exit block" style="filled" fillcolor=gray];
}
8 [label="Exit function getNothing" style="filled" fillcolor=red];
8 [label="Exit function getNothing" style="filled" fillcolor=red style="filled" fillcolor=gray];
}
0 -> {1};
1 -> {2};
2 -> {3};
3 -> {8} [label="onUncaughtException"];
3 -> {4} [style=dotted];
4 -> {5} [style=dotted];
5 -> {6 8} [style=dotted];
@@ -104,12 +103,11 @@ digraph smartcastToNothing_kt {
36 [label="Stub" style="filled" fillcolor=gray];
37 [label="Exit block" style="filled" fillcolor=gray];
}
38 [label="Exit function myListOf" style="filled" fillcolor=red];
38 [label="Exit function myListOf" style="filled" fillcolor=red style="filled" fillcolor=gray];
}
30 -> {31};
31 -> {32};
32 -> {33};
33 -> {38} [label="onUncaughtException"];
33 -> {34} [style=dotted];
34 -> {35} [style=dotted];
35 -> {36 38} [style=dotted];
@@ -266,17 +264,14 @@ digraph smartcastToNothing_kt {
65 -> {66};
66 -> {67};
67 -> {68};
68 -> {93} [label="onUncaughtException"];
68 -> {69} [style=dotted];
69 -> {70} [style=dotted];
70 -> {71} [style=dotted];
71 -> {93} [style=dotted label="onUncaughtException"];
71 -> {72} [style=dotted];
72 -> {73} [style=dotted];
73 -> {74} [style=dotted];
74 -> {75} [style=dotted];
75 -> {76} [style=dotted];
76 -> {93} [style=dotted label="onUncaughtException"];
76 -> {77} [style=dotted];
77 -> {78} [style=dotted];
78 -> {79} [style=dotted];
@@ -398,7 +393,6 @@ digraph smartcastToNothing_kt {
131 -> {132};
132 -> {133};
133 -> {134};
134 -> {142} [label="onUncaughtException"];
134 -> {135} [style=dotted];
135 -> {136} [style=dotted];
136 -> {137} [style=dotted];
@@ -32,12 +32,11 @@ digraph delegateWithAnonymousObject_kt {
11 [label="Stub" style="filled" fillcolor=gray];
12 [label="Exit block" style="filled" fillcolor=gray];
}
13 [label="Exit function delegate" style="filled" fillcolor=red];
13 [label="Exit function delegate" style="filled" fillcolor=red style="filled" fillcolor=gray];
}
5 -> {6};
6 -> {7};
7 -> {8};
8 -> {13} [label="onUncaughtException"];
8 -> {9} [style=dotted];
9 -> {10} [style=dotted];
10 -> {11 13} [style=dotted];
@@ -30,12 +30,11 @@ digraph plusAssignWithLambdaInRhs_kt {
9 [label="Function call: R|<local>/list|.R|kotlin/collections/plusAssign|<R|(kotlin/String) -> kotlin/String|>(...)" style="filled" fillcolor=gray];
10 [label="Exit block" style="filled" fillcolor=gray];
}
11 [label="Exit function test" style="filled" fillcolor=red];
11 [label="Exit function test" style="filled" fillcolor=red style="filled" fillcolor=gray];
}
0 -> {1};
1 -> {2};
2 -> {3};
3 -> {11} [label="onUncaughtException"];
3 -> {4} [style=dotted];
4 -> {5} [style=dotted];
5 -> {6} [style=dotted];
@@ -116,7 +116,6 @@ finally {
23 -> {24};
24 -> {25};
25 -> {26};
25 -> {30} [label="onUncaughtException"];
26 -> {27};
27 -> {30};
27 -> {28} [style=dotted];
@@ -205,7 +204,6 @@ finally {
48 -> {49};
49 -> {50};
50 -> {51};
50 -> {55} [label="onUncaughtException"];
51 -> {52};
52 -> {55};
52 -> {53} [style=dotted];
@@ -938,6 +938,9 @@ class ControlFlowGraphBuilder {
finallyEnterNodes.push(createFinallyBlockEnterNode(tryExpression))
}
// These edges should really be from `enterTryMainBlockNode`, but there is no practical difference
// so w/e. In fact, `enterTryExpressionNode` is just 100% redundant.
// TODO: this is more or less `addExceptionEdgesFrom(enterTryExpressionNode)`. Hmm.
for (catchEnterNode in catchNodes.top()) {
addEdge(enterTryExpressionNode, catchEnterNode)
}
@@ -959,11 +962,14 @@ class ControlFlowGraphBuilder {
// try { a } catch (e) { b } [finally { c }]
// \-----------------^
val nextNode = if (node.fir.finallyBlock != null) finallyEnterNodes.top() else exitTryExpressionNode
// Liveness of `exitTryExpressionNode` will be computed at the end since there are `catch`es.
// And the `finally` node is never dead unless the entire try-finally is dead.
addEdge(node, nextNode, propagateDeadness = false)
for (catchEnterNode in catchNodes.pop().asReversed()) {
catchBlocksInProgress.push(catchEnterNode)
// At least merge the data flow from enter + exit...but this doesn't really help,
// see the comment for `addExceptionEdgesFrom`.
// see the comment for `addExceptionEdgesFrom`. Better than nothing, though.
// Like `finally`, `catch` nodes are only dead if the entire try-catch is dead.
addEdge(node, catchEnterNode, propagateDeadness = false)
}
return node
@@ -975,9 +981,6 @@ class ControlFlowGraphBuilder {
if (tryExitNodes.top().fir.finallyBlock != null) {
// TODO: not sure this does anything?
addEdge(catchEnterNode, finallyEnterNodes.top(), propagateDeadness = false, label = UncaughtExceptionPath)
} else {
// TODO: this DEFINITELY does nothing, and is in fact incorrect if there are outer try-finally.
addEdge(catchEnterNode, exitTargetsForTry.top(), propagateDeadness = false, label = UncaughtExceptionPath)
}
lastNodes.push(catchEnterNode)
levelCounter++
@@ -1013,27 +1016,40 @@ class ControlFlowGraphBuilder {
edge.kind.isDead || edge.label != NormalPath
}
addEdge(exitNode, tryExitNode, isDead = allNormalInputsAreDead)
val nextExitLevel = addUncaughtExceptionEdgeFrom(exitNode)
// TODO: there should also be edges to outer catch blocks? Control flow can go like this:
// try { try { throw E2() } catch (e: E1) { } finally { } } catch (e: E2) { }
// \-----------------------------^ \-----------------^
// Wait, that's just `addExceptionEdgesFrom(exitNode)` again!
val nextExitLevel = exitTargetsForTry.top().level
val nextFinally = finallyEnterNodes.topOrNull()?.takeIf { it.level > nextExitLevel }
if (nextFinally != null) {
addEdge(exitNode, nextFinally, label = UncaughtExceptionPath, propagateDeadness = false)
}
val nextFinallyOrExitLevel = nextFinally?.level ?: nextExitLevel
// /-----------v
// f@ { try { return@f } finally { b }; c }
// \-----^
exitNode.addReturnEdges(exitTargetsForReturn, nextExitLevel)
exitNode.addReturnEdges(exitTargetsForReturn, nextFinallyOrExitLevel)
// /-----------v
// f@ while (x) { try { continue@f } finally { b }; c }
// ^------------------------------------/
exitNode.addReturnEdges(loopConditionEnterNodes, nextExitLevel)
exitNode.addReturnEdges(loopConditionEnterNodes, nextFinallyOrExitLevel)
// /-----------v
// f@ while (x) { try { break@f } finally { b }; c }
// \-----^
exitNode.addReturnEdges(loopExitNodes, nextExitLevel)
exitNode.addReturnEdges(loopExitNodes, nextFinallyOrExitLevel)
return exitNode
}
private fun <T : CFGNode<*>> CFGNode<*>.addReturnEdges(nodes: Stack<T>, minLevel: Int) {
for (node in nodes.all()) {
when {
node.level <= minLevel -> break
node.level < minLevel -> break
// TODO: this check is imprecise and can add redundant edges:
// x@{ try { return@x } finally {}; try {} finally { /* return@x target is in nonDirectJumps */ }
node !in nonDirectJumps -> continue
// TODO: if the input to finally with that label is dead, then so should be the exit probably
node.returnPathIsBackwards -> addBackEdge(this, node, label = node.returnPathLabel)
else -> addEdge(this, node, propagateDeadness = false, label = node.returnPathLabel)
}
@@ -1050,25 +1066,17 @@ class ControlFlowGraphBuilder {
return node
}
private fun addUncaughtExceptionEdgeFrom(node: CFGNode<*>): Int {
val nextExit = exitTargetsForTry.top()
val nextFinally = finallyEnterNodes.topOrNull()
// TODO: this edge is probably redundant if chose `nextExit`
val nextNode = if (nextFinally != null && nextFinally.level > nextExit.level) nextFinally else nextExit
addEdge(node, nextNode, propagateDeadness = false, label = UncaughtExceptionPath)
return nextNode.level
}
// TODO: these edges are true for literally any node in the graph. Their existence for *some* nodes
// might lead to a false sense of security, but things are broken. This should be some sort of implicit knowledge
// instead of requiring a ton of edges?
// TODO: these edges are true for literally any node in the graph. Their existence for *some* nodes might lead
// to a false sense of security, but things are broken. This should be some sort of implicit knowledge instead
// of requiring a ton of edges? (Some nodes never throw, but calls are never safe, and most useful stuff is calls.)
// var x: Any?
// x = ""
// try {
// x = null
// f() // throws
// listOf(1, 2, 3).single()
// x = ""
// } catch (e: Throwable) { x.length } // oops
// Just look at `enterTryExpression` - the edges it adds are literally `addExceptionEdgesFrom(tryExpressionEnterNode)`.
// R8 devs say they tried the "implicit knowledge" way but failed and decided to add all the edges - bad sign...
private fun addExceptionEdgesFrom(node: CFGNode<*>) {
val nextCatch = catchNodes.topOrNull()
if (nextCatch != null) {
@@ -1076,7 +1084,10 @@ class ControlFlowGraphBuilder {
addEdge(node, catchEnterNode, propagateDeadness = false)
}
}
addUncaughtExceptionEdgeFrom(node)
val nextFinally = finallyEnterNodes.topOrNull()
if (nextFinally != null && nextFinally.level > exitTargetsForTry.top().level) {
addEdge(node, nextFinally, propagateDeadness = false, label = UncaughtExceptionPath)
}
}
//this is a workaround to make function call dead when call is completed _after_ building its node in the graph
@@ -0,0 +1,223 @@
fun foo(): Int = 42
object ThrowInTryWithCatch {
private val p: String
init {
try {
throw Exception()
} catch (e: Exception) {
}
p = "OK"
}
}
object ThrowInTryWithCatchAndFinally {
private val p: String
init {
try {
throw Exception()
} catch (e: Exception) {
} finally {
}
p = "OK"
}
}
object ThrowInFinally {
private val p: String
init {
try {
foo()
} catch (e: Exception) {
} finally {
throw Exception()
}
p = "OK"
}
}
object RethrowInCatch {
private val p: String
init {
try {
foo()
} catch (e: Exception) {
throw e
}
p = "OK"
}
}
object RethrowInCatchWithFinally {
private val p: String
init {
try {
foo()
} catch (e: Exception) {
throw e
} finally {
}
p = "OK"
}
}
object InnerTryWithCatch {
private val p: String
init {
try {
foo()
} catch (e: Exception) {
try {
throw e
} catch (ee: Exception) {
}
}
p = "OK"
}
}
object InnerTryWithFinally {
private val p: String
init {
try {
foo()
} catch (e: Exception) {
try {
throw e
} finally {
}
}
p = "OK"
}
}
object InnerTryWithCatchAndFinally {
private val p: String
init {
try {
foo()
} catch (e: Exception) {
try {
throw e
} catch (ee: Exception) {
} finally {
}
}
p = "OK"
}
}
object InnerCatch {
private val p: String
init {
try {
foo()
} catch (e: Exception) {
try {
foo()
} catch (ee: Exception) {
throw ee
}
}
p = "OK"
}
}
object InnerCatchWithFinally {
private val p: String
init {
try {
foo()
} catch (e: Exception) {
try {
foo()
} catch (ee: Exception) {
throw ee
} finally {
}
}
p = "OK"
}
}
object InnerCatchOuterRethrow {
private val p: String
init {
try {
foo()
} catch (e: Exception) {
try {
foo()
} catch (ee: Exception) {
throw e
}
}
p = "OK"
}
}
object InnerCatchOuterRethrowWithFinally {
private val p: String
init {
try {
foo()
} catch (e: Exception) {
try {
foo()
} catch (ee: Exception) {
throw e
} finally {
}
}
p = "OK"
}
}
object InnerFinally {
private val p: String
init {
try {
foo()
} catch (e: Exception) {
try {
foo()
} finally {
throw e
}
}
p = "OK"
}
}
object InnerFinallyWithCatch {
private val p: String
init {
try {
foo()
} catch (e: Exception) {
try {
foo()
} catch (ee: Exception) {
} finally {
throw e
}
}
p = "OK"
}
}
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
fun foo(): Int = 42