// errorcheck // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Test compiler diagnosis of function missing return statements. // See issue 65 and golang.org/s/go11return. package p type T int var x interface{} var c chan int func external() int // ok func _() int { } // ERROR "missing return" func _() int { print(1) } // ERROR "missing return" // return is okay func _() int { print(1) return 2 } // goto is okay func _() int { L: print(1) goto L } // panic is okay func _() int { print(1) panic(2) } // but only builtin panic func _() int { var panic = func(int) {} print(1) panic(2) } // ERROR "missing return" // block ending in terminating statement is okay func _() int { { print(1) return 2 } } // block ending in terminating statement is okay func _() int { L: { print(1) goto L } } // block ending in terminating statement is okay func _() int { print(1) { panic(2) } } // adding more code - even though it is dead - now requires a return func _() int { print(1) return 2 print(3) } // ERROR "missing return" func _() int { L: print(1) goto L print(3) } // ERROR "missing return" func _() int { print(1) panic(2) print(3) } // ERROR "missing return" func _() int { { print(1) return 2 print(3) } } // ERROR "missing return" func _() int { L: { print(1) goto L print(3) } } // ERROR "missing return" func _() int { print(1) { panic(2) print(3) } } // ERROR "missing return" func _() int { { print(1) return 2 } print(3) } // ERROR "missing return" func _() int { L: { print(1) goto L } print(3) } // ERROR "missing return" func _() int { print(1) { panic(2) } print(3) } // ERROR "missing return" // even an empty dead block triggers the message, because it // becomes the final statement. func _() int { print(1) return 2 {} } // ERROR "missing return" func _() int { L: print(1) goto L {} } // ERROR "missing return" func _() int { print(1) panic(2) {} } // ERROR "missing return" func _() int { { print(1) return 2 {} } } // ERROR "missing return" func _() int { L: { print(1) goto L {} } } // ERROR "missing return" func _() int { print(1) { panic(2) {} } } // ERROR "missing return" func _() int { { print(1) return 2 } {} } // ERROR "missing return" func _() int { L: { print(1) goto L } {} } // ERROR "missing return" func _() int { print(1) { panic(2) } {} } // ERROR "missing return" // if-else chain with final else and all terminating is okay func _() int { print(1) if x == nil { panic(2) } else { panic(3) } } func _() int { L: print(1) if x == nil { panic(2) } else { goto L } } func _() int { L: print(1) if x == nil { panic(2) } else if x == 1 { return 0 } else if x != 2 { panic(3) } else { goto L } } // if-else chain missing final else is not okay, even if the // conditions cover every possible case. func _() int { print(1) if x == nil { panic(2) } else if x != nil { panic(3) } } // ERROR "missing return" func _() int { print(1) if x == nil { panic(2) } } // ERROR "missing return" func _() int { L: print(1) if x == nil { panic(2) } else if x == 1 { return 0 } else if x != 1 { panic(3) } } // ERROR "missing return" // for { loops that never break are okay. func _() int { print(1) for {} } func _() int { for { for { break } } } func _() int { for { L: for { break L } } } // for { loops that break are not okay. func _() int { print(1) for { break } } // ERROR "missing return" func _() int { for { for { } break } } // ERROR "missing return" func _() int { L: for { for { break L } } } // ERROR "missing return" // if there's a condition - even "true" - the loops are no longer syntactically terminating func _() int { print(1) for x == nil {} } // ERROR "missing return" func _() int { for x == nil { for { break } } } // ERROR "missing return" func _() int { for x == nil { L: for { break L } } } // ERROR "missing return" func _() int { print(1) for true {} } // ERROR "missing return" func _() int { for true { for { break } } } // ERROR "missing return" func _() int { for true { L: for { break L } } } // ERROR "missing return" // select in which all cases terminate and none break are okay. func _() int { print(1) select{} } func _() int { print(1) select { case <-c: print(2) panic("abc") } } func _() int { print(1) select { case <-c: print(2) for{} } } func _() int { L: print(1) select { case <-c: print(2) panic("abc") case c <- 1: print(2) goto L } } func _() int { print(1) select { case <-c: print(2) panic("abc") default: select{} } } // if any cases don't terminate, the select isn't okay anymore func _() int { print(1) select { case <-c: print(2) } } // ERROR "missing return" func _() int { L: print(1) select { case <-c: print(2) panic("abc") goto L case c <- 1: print(2) } } // ERROR "missing return" func _() int { print(1) select { case <-c: print(2) panic("abc") default: print(2) } } // ERROR "missing return" // if any breaks refer to the select, the select isn't okay anymore, even if they're dead func _() int { print(1) select{ default: break } } // ERROR "missing return" func _() int { print(1) select { case <-c: print(2) panic("abc") break } } // ERROR "missing return" func _() int { print(1) L: select { case <-c: print(2) for{ break L } } } // ERROR "missing return" func _() int { print(1) L: select { case <-c: print(2) panic("abc") case c <- 1: print(2) break L } } // ERROR "missing return" func _() int { print(1) select { case <-c: print(1) panic("abc") default: select{} break } } // ERROR "missing return" // switch with default in which all cases terminate is okay func _() int { print(1) switch x { case 1: print(2) panic(3) default: return 4 } } func _() int { print(1) switch x { default: return 4 case 1: print(2) panic(3) } } func _() int { print(1) switch x { case 1: print(2) fallthrough default: return 4 } } // if no default or some case doesn't terminate, switch is no longer okay func _() int { print(1) switch { } } // ERROR "missing return" func _() int { print(1) switch x { case 1: print(2) panic(3) case 2: return 4 } } // ERROR "missing return" func _() int { print(1) switch x { case 2: return 4 case 1: print(2) panic(3) } } // ERROR "missing return" func _() int { print(1) switch x { case 1: print(2) fallthrough case 2: return 4 } } // ERROR "missing return" func _() int { print(1) switch x { case 1: print(2) panic(3) } } // ERROR "missing return" // if any breaks refer to the switch, switch is no longer okay func _() int { print(1) L: switch x { case 1: print(2) panic(3) break L default: return 4 } } // ERROR "missing return" func _() int { print(1) switch x { default: return 4 break case 1: print(2) panic(3) } } // ERROR "missing return" func _() int { print(1) L: switch x { case 1: print(2) for { break L } default: return 4 } } // ERROR "missing return" // type switch with default in which all cases terminate is okay func _() int { print(1) switch x.(type) { case int: print(2) panic(3) default: return 4 } } func _() int { print(1) switch x.(type) { default: return 4 case int: print(2) panic(3) } } func _() int { print(1) switch x.(type) { case int: print(2) fallthrough default: return 4 } } // if no default or some case doesn't terminate, switch is no longer okay func _() int { print(1) switch { } } // ERROR "missing return" func _() int { print(1) switch x.(type) { case int: print(2) panic(3) case float64: return 4 } } // ERROR "missing return" func _() int { print(1) switch x.(type) { case float64: return 4 case int: print(2) panic(3) } } // ERROR "missing return" func _() int { print(1) switch x.(type) { case int: print(2) fallthrough case float64: return 4 } } // ERROR "missing return" func _() int { print(1) switch x.(type) { case int: print(2) panic(3) } } // ERROR "missing return" // if any breaks refer to the switch, switch is no longer okay func _() int { print(1) L: switch x.(type) { case int: print(2) panic(3) break L default: return 4 } } // ERROR "missing return" func _() int { print(1) switch x.(type) { default: return 4 break case int: print(2) panic(3) } } // ERROR "missing return" func _() int { print(1) L: switch x.(type) { case int: print(2) for { break L } default: return 4 } } // ERROR "missing return" // again, but without the leading print(1). // testing that everything works when the terminating statement is first. func _() int { } // ERROR "missing return" // return is okay func _() int { return 2 } // goto is okay func _() int { L: goto L } // panic is okay func _() int { panic(2) } // but only builtin panic func _() int { var panic = func(int) {} panic(2) } // ERROR "missing return" // block ending in terminating statement is okay func _() int { { return 2 } } // block ending in terminating statement is okay func _() int { L: { goto L } } // block ending in terminating statement is okay func _() int { { panic(2) } } // adding more code - even though it is dead - now requires a return func _() int { return 2 print(3) } // ERROR "missing return" func _() int { L: goto L print(3) } // ERROR "missing return" func _() int { panic(2) print(3) } // ERROR "missing return" func _() int { { return 2 print(3) } } // ERROR "missing return" func _() int { L: { goto L print(3) } } // ERROR "missing return" func _() int { { panic(2) print(3) } } // ERROR "missing return" func _() int { { return 2 } print(3) } // ERROR "missing return" func _() int { L: { goto L } print(3) } // ERROR "missing return" func _() int { { panic(2) } print(3) } // ERROR "missing return" // even an empty dead block triggers the message, because it // becomes the final statement. func _() int { return 2 {} } // ERROR "missing return" func _() int { L: goto L {} } // ERROR "missing return" func _() int { panic(2) {} } // ERROR "missing return" func _() int { { return 2 {} } } // ERROR "missing return" func _() int { L: { goto L {} } } // ERROR "missing return" func _() int { { panic(2) {} } } // ERROR "missing return" func _() int { { return 2 } {} } // ERROR "missing return" func _() int { L: { goto L } {} } // ERROR "missing return" func _() int { { panic(2) } {} } // ERROR "missing return" // if-else chain with final else and all terminating is okay func _() int { if x == nil { panic(2) } else { panic(3) } } func _() int { L: if x == nil { panic(2) } else { goto L } } func _() int { L: if x == nil { panic(2) } else if x == 1 { return 0 } else if x != 2 { panic(3) } else { goto L } } // if-else chain missing final else is not okay, even if the // conditions cover every possible case. func _() int { if x == nil { panic(2) } else if x != nil { panic(3) } } // ERROR "missing return" func _() int { if x == nil { panic(2) } } // ERROR "missing return" func _() int { L: if x == nil { panic(2) } else if x == 1 { return 0 } else if x != 1 { panic(3) } } // ERROR "missing return" // for { loops that never break are okay. func _() int { for {} } func _() int { for { for { break } } } func _() int { for { L: for { break L } } } // for { loops that break are not okay. func _() int { for { break } } // ERROR "missing return" func _() int { for { for { } break } } // ERROR "missing return" func _() int { L: for { for { break L } } } // ERROR "missing return" // if there's a condition - even "true" - the loops are no longer syntactically terminating func _() int { for x == nil {} } // ERROR "missing return" func _() int { for x == nil { for { break } } } // ERROR "missing return" func _() int { for x == nil { L: for { break L } } } // ERROR "missing return" func _() int { for true {} } // ERROR "missing return" func _() int { for true { for { break } } } // ERROR "missing return" func _() int { for true { L: for { break L } } } // ERROR "missing return" // select in which all cases terminate and none break are okay. func _() int { select{} } func _() int { select { case <-c: print(2) panic("abc") } } func _() int { select { case <-c: print(2) for{} } } func _() int { L: select { case <-c: print(2) panic("abc") case c <- 1: print(2) goto L } } func _() int { select { case <-c: print(2) panic("abc") default: select{} } } // if any cases don't terminate, the select isn't okay anymore func _() int { select { case <-c: print(2) } } // ERROR "missing return" func _() int { L: select { case <-c: print(2) panic("abc") goto L case c <- 1: print(2) } } // ERROR "missing return" func _() int { select { case <-c: print(2) panic("abc") default: print(2) } } // ERROR "missing return" // if any breaks refer to the select, the select isn't okay anymore, even if they're dead func _() int { select{ default: break } } // ERROR "missing return" func _() int { select { case <-c: print(2) panic("abc") break } } // ERROR "missing return" func _() int { L: select { case <-c: print(2) for{ break L } } } // ERROR "missing return" func _() int { L: select { case <-c: print(2) panic("abc") case c <- 1: print(2) break L } } // ERROR "missing return" func _() int { select { case <-c: panic("abc") default: select{} break } } // ERROR "missing return" // switch with default in which all cases terminate is okay func _() int { switch x { case 1: print(2) panic(3) default: return 4 } } func _() int { switch x { default: return 4 case 1: print(2) panic(3) } } func _() int { switch x { case 1: print(2) fallthrough default: return 4 } } // if no default or some case doesn't terminate, switch is no longer okay func _() int { switch { } } // ERROR "missing return" func _() int { switch x { case 1: print(2) panic(3) case 2: return 4 } } // ERROR "missing return" func _() int { switch x { case 2: return 4 case 1: print(2) panic(3) } } // ERROR "missing return" func _() int { switch x { case 1: print(2) fallthrough case 2: return 4 } } // ERROR "missing return" func _() int { switch x { case 1: print(2) panic(3) } } // ERROR "missing return" // if any breaks refer to the switch, switch is no longer okay func _() int { L: switch x { case 1: print(2) panic(3) break L default: return 4 } } // ERROR "missing return" func _() int { switch x { default: return 4 break case 1: print(2) panic(3) } } // ERROR "missing return" func _() int { L: switch x { case 1: print(2) for { break L } default: return 4 } } // ERROR "missing return" // type switch with default in which all cases terminate is okay func _() int { switch x.(type) { case int: print(2) panic(3) default: return 4 } } func _() int { switch x.(type) { default: return 4 case int: print(2) panic(3) } } func _() int { switch x.(type) { case int: print(2) fallthrough default: return 4 } } // if no default or some case doesn't terminate, switch is no longer okay func _() int { switch { } } // ERROR "missing return" func _() int { switch x.(type) { case int: print(2) panic(3) case float64: return 4 } } // ERROR "missing return" func _() int { switch x.(type) { case float64: return 4 case int: print(2) panic(3) } } // ERROR "missing return" func _() int { switch x.(type) { case int: print(2) fallthrough case float64: return 4 } } // ERROR "missing return" func _() int { switch x.(type) { case int: print(2) panic(3) } } // ERROR "missing return" // if any breaks refer to the switch, switch is no longer okay func _() int { L: switch x.(type) { case int: print(2) panic(3) break L default: return 4 } } // ERROR "missing return" func _() int { switch x.(type) { default: return 4 break case int: print(2) panic(3) } } // ERROR "missing return" func _() int { L: switch x.(type) { case int: print(2) for { break L } default: return 4 } } // ERROR "missing return" /**/