[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:
+117
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user