[FIR] finally CFG exit node jump edges should match enter node edges

Jump edge targets are maintained globally within the CFG builder and are
added indiscriminately to `finally` exit nodes. This means that a
`finally` exit node could have a jump edge added which doesn't match how
the `finally` block was entered. Make sure edges are only added to the
exit node if they also exist on the enter node.

#KT-60723 Fixed
This commit is contained in:
Brian Norman
2023-07-18 14:26:44 -05:00
committed by Space Team
parent 5ab4229ee5
commit 1acdb3c143
9 changed files with 1077 additions and 3 deletions
@@ -0,0 +1,117 @@
// DUMP_CFG
interface A {
fun aaa()
}
interface B {
fun bbb()
}
interface C {
fun ccc()
}
fun breakInTry_withNestedFinally() {
var x: Any? = null
while (true) {
try {
x as A
break
} finally {
try {
x as B
} finally {
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be error
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
}
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be error
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be ok
}
<!UNREACHABLE_CODE!>x.<!UNRESOLVED_REFERENCE!>aaa<!>()<!> // should be error
<!UNREACHABLE_CODE!>x.<!UNRESOLVED_REFERENCE!>bbb<!>()<!> // should be ok
}
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be ok
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be ok
}
fun returnInCatch() {
var x: Any? = null
try {
x as A
} catch (e: Exception) {
x as B
return
} finally {
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be error
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
}
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be ok
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
}
fun returnInCatch_insideFinally() {
var x: Any? = null
try {
x as C
} finally {
try {
x as A
} catch (e: Exception) {
x as B
return
} finally {
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be error
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
x.<!UNRESOLVED_REFERENCE!>ccc<!>() // should be error
}
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be ok
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
x.<!UNRESOLVED_REFERENCE!>ccc<!>() // should be error
}
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be ok
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
x.<!UNRESOLVED_REFERENCE!>ccc<!>() // should be ok
}
fun breakInCatch() {
var x: Any? = null
while (true) {
try {
x as A
} catch (e: Exception) {
x as B
break
} finally {
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be error
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
}
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be ok
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
}
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be error
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be ok
}
fun returnInFinally_insideTry_nonLocal() {
var x: Any? = null
run {
try {
x as B
try {
x as A
} finally {
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be error
<!DEBUG_INFO_SMARTCAST!>x<!>.bbb() // should be ok
return
}
} finally {
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be error
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
}
<!UNREACHABLE_CODE!>x.<!UNRESOLVED_REFERENCE!>aaa<!>()<!> // should be error
<!UNREACHABLE_CODE!>x.<!UNRESOLVED_REFERENCE!>bbb<!>()<!> // should be error
}
<!UNREACHABLE_CODE!>x.<!UNRESOLVED_REFERENCE!>aaa<!>()<!> // should be error
<!UNREACHABLE_CODE!>x.<!UNRESOLVED_REFERENCE!>bbb<!>()<!> // should be error
}