diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c index 133936e0f1..aca30dc1cf 100644 --- a/src/cmd/gc/closure.c +++ b/src/cmd/gc/closure.c @@ -60,6 +60,7 @@ closurebody(NodeList *body) func = curfn; func->nbody = body; + func->endlineno = lineno; funcbody(func); // closure-specific variables are hanging off the @@ -154,6 +155,7 @@ makeclosure(Node *func, int nowrap) declare(xfunc->nname, PFUNC); xfunc->nname->funcdepth = func->funcdepth; xfunc->funcdepth = func->funcdepth; + xfunc->endlineno = func->endlineno; // declare variables holding addresses taken from closure // and initialize in entry prologue. diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c index 1ffddd5384..ee5b9e939b 100644 --- a/src/cmd/gc/fmt.c +++ b/src/cmd/gc/fmt.c @@ -168,7 +168,7 @@ Lconv(Fmt *fp) lno = a[i].incl->line - 1; // now print out start of this file } if(n == 0) - fmtprint(fp, ""); + fmtprint(fp, ""); return 0; } diff --git a/test/return.go b/test/return.go index aebbf78b74..dcf32f86ff 100644 --- a/test/return.go +++ b/test/return.go @@ -1450,4 +1450,1440 @@ L: } } // ERROR "missing return" +// again, with func literals + +var _ = func() int { +} // ERROR "missing return" + +var _ = func() int { + print(1) +} // ERROR "missing return" + +// return is okay +var _ = func() int { + print(1) + return 2 +} + +// goto is okay +var _ = func() int { +L: + print(1) + goto L +} + +// panic is okay +var _ = func() int { + print(1) + panic(2) +} + +// but only builtin panic +var _ = func() int { + var panic = func(int) {} + print(1) + panic(2) +} // ERROR "missing return" + +// block ending in terminating statement is okay +var _ = func() int { + { + print(1) + return 2 + } +} + +// block ending in terminating statement is okay +var _ = func() int { +L: + { + print(1) + goto L + } +} + +// block ending in terminating statement is okay +var _ = func() int { + print(1) + { + panic(2) + } +} + +// adding more code - even though it is dead - now requires a return + +var _ = func() int { + print(1) + return 2 + print(3) +} // ERROR "missing return" + +var _ = func() int { +L: + print(1) + goto L + print(3) +} // ERROR "missing return" + +var _ = func() int { + print(1) + panic(2) + print(3) +} // ERROR "missing return" + +var _ = func() int { + { + print(1) + return 2 + print(3) + } +} // ERROR "missing return" + +var _ = func() int { +L: + { + print(1) + goto L + print(3) + } +} // ERROR "missing return" + +var _ = func() int { + print(1) + { + panic(2) + print(3) + } +} // ERROR "missing return" + +var _ = func() int { + { + print(1) + return 2 + } + print(3) +} // ERROR "missing return" + +var _ = func() int { +L: + { + print(1) + goto L + } + print(3) +} // ERROR "missing return" + +var _ = 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. + +var _ = func() int { + print(1) + return 2 + {} +} // ERROR "missing return" + +var _ = func() int { +L: + print(1) + goto L + {} +} // ERROR "missing return" + +var _ = func() int { + print(1) + panic(2) + {} +} // ERROR "missing return" + +var _ = func() int { + { + print(1) + return 2 + {} + } +} // ERROR "missing return" + +var _ = func() int { +L: + { + print(1) + goto L + {} + } +} // ERROR "missing return" + +var _ = func() int { + print(1) + { + panic(2) + {} + } +} // ERROR "missing return" + +var _ = func() int { + { + print(1) + return 2 + } + {} +} // ERROR "missing return" + +var _ = func() int { +L: + { + print(1) + goto L + } + {} +} // ERROR "missing return" + +var _ = func() int { + print(1) + { + panic(2) + } + {} +} // ERROR "missing return" + +// if-else chain with final else and all terminating is okay + +var _ = func() int { + print(1) + if x == nil { + panic(2) + } else { + panic(3) + } +} + +var _ = func() int { +L: + print(1) + if x == nil { + panic(2) + } else { + goto L + } +} + +var _ = 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. + +var _ = func() int { + print(1) + if x == nil { + panic(2) + } else if x != nil { + panic(3) + } +} // ERROR "missing return" + +var _ = func() int { + print(1) + if x == nil { + panic(2) + } +} // ERROR "missing return" + +var _ = 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. + +var _ = func() int { + print(1) + for {} +} + +var _ = func() int { + for { + for { + break + } + } +} + +var _ = func() int { + for { + L: + for { + break L + } + } +} + +// for { loops that break are not okay. + +var _ = func() int { + print(1) + for { break } +} // ERROR "missing return" + +var _ = func() int { + for { + for { + } + break + } +} // ERROR "missing return" + +var _ = func() int { +L: + for { + for { + break L + } + } +} // ERROR "missing return" + +// if there's a condition - even "true" - the loops are no longer syntactically terminating + +var _ = func() int { + print(1) + for x == nil {} +} // ERROR "missing return" + +var _ = func() int { + for x == nil { + for { + break + } + } +} // ERROR "missing return" + +var _ = func() int { + for x == nil { + L: + for { + break L + } + } +} // ERROR "missing return" + +var _ = func() int { + print(1) + for true {} +} // ERROR "missing return" + +var _ = func() int { + for true { + for { + break + } + } +} // ERROR "missing return" + +var _ = func() int { + for true { + L: + for { + break L + } + } +} // ERROR "missing return" + +// select in which all cases terminate and none break are okay. + +var _ = func() int { + print(1) + select{} +} + +var _ = func() int { + print(1) + select { + case <-c: + print(2) + panic("abc") + } +} + +var _ = func() int { + print(1) + select { + case <-c: + print(2) + for{} + } +} + +var _ = func() int { +L: + print(1) + select { + case <-c: + print(2) + panic("abc") + case c <- 1: + print(2) + goto L + } +} + +var _ = 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 + +var _ = func() int { + print(1) + select { + case <-c: + print(2) + } +} // ERROR "missing return" + +var _ = func() int { +L: + print(1) + select { + case <-c: + print(2) + panic("abc") + goto L + case c <- 1: + print(2) + } +} // ERROR "missing return" + + +var _ = 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 + +var _ = func() int { + print(1) + select{ default: break } +} // ERROR "missing return" + +var _ = func() int { + print(1) + select { + case <-c: + print(2) + panic("abc") + break + } +} // ERROR "missing return" + +var _ = func() int { + print(1) +L: + select { + case <-c: + print(2) + for{ break L } + } +} // ERROR "missing return" + +var _ = func() int { + print(1) +L: + select { + case <-c: + print(2) + panic("abc") + case c <- 1: + print(2) + break L + } +} // ERROR "missing return" + +var _ = 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 + +var _ = func() int { + print(1) + switch x { + case 1: + print(2) + panic(3) + default: + return 4 + } +} + +var _ = func() int { + print(1) + switch x { + default: + return 4 + case 1: + print(2) + panic(3) + } +} + +var _ = 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 + +var _ = func() int { + print(1) + switch { + } +} // ERROR "missing return" + + +var _ = func() int { + print(1) + switch x { + case 1: + print(2) + panic(3) + case 2: + return 4 + } +} // ERROR "missing return" + +var _ = func() int { + print(1) + switch x { + case 2: + return 4 + case 1: + print(2) + panic(3) + } +} // ERROR "missing return" + +var _ = func() int { + print(1) + switch x { + case 1: + print(2) + fallthrough + case 2: + return 4 + } +} // ERROR "missing return" + +var _ = 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 + +var _ = func() int { + print(1) +L: + switch x { + case 1: + print(2) + panic(3) + break L + default: + return 4 + } +} // ERROR "missing return" + +var _ = func() int { + print(1) + switch x { + default: + return 4 + break + case 1: + print(2) + panic(3) + } +} // ERROR "missing return" + +var _ = 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 + +var _ = func() int { + print(1) + switch x.(type) { + case int: + print(2) + panic(3) + default: + return 4 + } +} + +var _ = func() int { + print(1) + switch x.(type) { + default: + return 4 + case int: + print(2) + panic(3) + } +} + +var _ = 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 + +var _ = func() int { + print(1) + switch { + } +} // ERROR "missing return" + + +var _ = func() int { + print(1) + switch x.(type) { + case int: + print(2) + panic(3) + case float64: + return 4 + } +} // ERROR "missing return" + +var _ = func() int { + print(1) + switch x.(type) { + case float64: + return 4 + case int: + print(2) + panic(3) + } +} // ERROR "missing return" + +var _ = func() int { + print(1) + switch x.(type) { + case int: + print(2) + fallthrough + case float64: + return 4 + } +} // ERROR "missing return" + +var _ = 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 + +var _ = func() int { + print(1) +L: + switch x.(type) { + case int: + print(2) + panic(3) + break L + default: + return 4 + } +} // ERROR "missing return" + +var _ = func() int { + print(1) + switch x.(type) { + default: + return 4 + break + case int: + print(2) + panic(3) + } +} // ERROR "missing return" + +var _ = 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. + +var _ = func() int { +} // ERROR "missing return" + +// return is okay +var _ = func() int { + return 2 +} + +// goto is okay +var _ = func() int { +L: + goto L +} + +// panic is okay +var _ = func() int { + panic(2) +} + +// but only builtin panic +var _ = func() int { + var panic = func(int) {} + panic(2) +} // ERROR "missing return" + +// block ending in terminating statement is okay +var _ = func() int { + { + return 2 + } +} + +// block ending in terminating statement is okay +var _ = func() int { +L: + { + goto L + } +} + +// block ending in terminating statement is okay +var _ = func() int { + { + panic(2) + } +} + +// adding more code - even though it is dead - now requires a return + +var _ = func() int { + return 2 + print(3) +} // ERROR "missing return" + +var _ = func() int { +L: + goto L + print(3) +} // ERROR "missing return" + +var _ = func() int { + panic(2) + print(3) +} // ERROR "missing return" + +var _ = func() int { + { + return 2 + print(3) + } +} // ERROR "missing return" + +var _ = func() int { +L: + { + goto L + print(3) + } +} // ERROR "missing return" + +var _ = func() int { + { + panic(2) + print(3) + } +} // ERROR "missing return" + +var _ = func() int { + { + return 2 + } + print(3) +} // ERROR "missing return" + +var _ = func() int { +L: + { + goto L + } + print(3) +} // ERROR "missing return" + +var _ = func() int { + { + panic(2) + } + print(3) +} // ERROR "missing return" + +// even an empty dead block triggers the message, because it +// becomes the final statement. + +var _ = func() int { + return 2 + {} +} // ERROR "missing return" + +var _ = func() int { +L: + goto L + {} +} // ERROR "missing return" + +var _ = func() int { + panic(2) + {} +} // ERROR "missing return" + +var _ = func() int { + { + return 2 + {} + } +} // ERROR "missing return" + +var _ = func() int { +L: + { + goto L + {} + } +} // ERROR "missing return" + +var _ = func() int { + { + panic(2) + {} + } +} // ERROR "missing return" + +var _ = func() int { + { + return 2 + } + {} +} // ERROR "missing return" + +var _ = func() int { +L: + { + goto L + } + {} +} // ERROR "missing return" + +var _ = func() int { + { + panic(2) + } + {} +} // ERROR "missing return" + +// if-else chain with final else and all terminating is okay + +var _ = func() int { + if x == nil { + panic(2) + } else { + panic(3) + } +} + +var _ = func() int { +L: + if x == nil { + panic(2) + } else { + goto L + } +} + +var _ = 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. + +var _ = func() int { + if x == nil { + panic(2) + } else if x != nil { + panic(3) + } +} // ERROR "missing return" + +var _ = func() int { + if x == nil { + panic(2) + } +} // ERROR "missing return" + +var _ = 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. + +var _ = func() int { + for {} +} + +var _ = func() int { + for { + for { + break + } + } +} + +var _ = func() int { + for { + L: + for { + break L + } + } +} + +// for { loops that break are not okay. + +var _ = func() int { + for { break } +} // ERROR "missing return" + +var _ = func() int { + for { + for { + } + break + } +} // ERROR "missing return" + +var _ = func() int { +L: + for { + for { + break L + } + } +} // ERROR "missing return" + +// if there's a condition - even "true" - the loops are no longer syntactically terminating + +var _ = func() int { + for x == nil {} +} // ERROR "missing return" + +var _ = func() int { + for x == nil { + for { + break + } + } +} // ERROR "missing return" + +var _ = func() int { + for x == nil { + L: + for { + break L + } + } +} // ERROR "missing return" + +var _ = func() int { + for true {} +} // ERROR "missing return" + +var _ = func() int { + for true { + for { + break + } + } +} // ERROR "missing return" + +var _ = func() int { + for true { + L: + for { + break L + } + } +} // ERROR "missing return" + +// select in which all cases terminate and none break are okay. + +var _ = func() int { + select{} +} + +var _ = func() int { + select { + case <-c: + print(2) + panic("abc") + } +} + +var _ = func() int { + select { + case <-c: + print(2) + for{} + } +} + +var _ = func() int { +L: + select { + case <-c: + print(2) + panic("abc") + case c <- 1: + print(2) + goto L + } +} + +var _ = func() int { + select { + case <-c: + print(2) + panic("abc") + default: + select{} + } +} + +// if any cases don't terminate, the select isn't okay anymore + +var _ = func() int { + select { + case <-c: + print(2) + } +} // ERROR "missing return" + +var _ = func() int { +L: + select { + case <-c: + print(2) + panic("abc") + goto L + case c <- 1: + print(2) + } +} // ERROR "missing return" + + +var _ = 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 + +var _ = func() int { + select{ default: break } +} // ERROR "missing return" + +var _ = func() int { + select { + case <-c: + print(2) + panic("abc") + break + } +} // ERROR "missing return" + +var _ = func() int { +L: + select { + case <-c: + print(2) + for{ break L } + } +} // ERROR "missing return" + +var _ = func() int { +L: + select { + case <-c: + print(2) + panic("abc") + case c <- 1: + print(2) + break L + } +} // ERROR "missing return" + +var _ = func() int { + select { + case <-c: + panic("abc") + default: + select{} + break + } +} // ERROR "missing return" + +// switch with default in which all cases terminate is okay + +var _ = func() int { + switch x { + case 1: + print(2) + panic(3) + default: + return 4 + } +} + +var _ = func() int { + switch x { + default: + return 4 + case 1: + print(2) + panic(3) + } +} + +var _ = 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 + +var _ = func() int { + switch { + } +} // ERROR "missing return" + + +var _ = func() int { + switch x { + case 1: + print(2) + panic(3) + case 2: + return 4 + } +} // ERROR "missing return" + +var _ = func() int { + switch x { + case 2: + return 4 + case 1: + print(2) + panic(3) + } +} // ERROR "missing return" + +var _ = func() int { + switch x { + case 1: + print(2) + fallthrough + case 2: + return 4 + } +} // ERROR "missing return" + +var _ = 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 + +var _ = func() int { +L: + switch x { + case 1: + print(2) + panic(3) + break L + default: + return 4 + } +} // ERROR "missing return" + +var _ = func() int { + switch x { + default: + return 4 + break + case 1: + print(2) + panic(3) + } +} // ERROR "missing return" + +var _ = 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 + +var _ = func() int { + switch x.(type) { + case int: + print(2) + panic(3) + default: + return 4 + } +} + +var _ = func() int { + switch x.(type) { + default: + return 4 + case int: + print(2) + panic(3) + } +} + +var _ = 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 + +var _ = func() int { + switch { + } +} // ERROR "missing return" + + +var _ = func() int { + switch x.(type) { + case int: + print(2) + panic(3) + case float64: + return 4 + } +} // ERROR "missing return" + +var _ = func() int { + switch x.(type) { + case float64: + return 4 + case int: + print(2) + panic(3) + } +} // ERROR "missing return" + +var _ = func() int { + switch x.(type) { + case int: + print(2) + fallthrough + case float64: + return 4 + } +} // ERROR "missing return" + +var _ = 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 + +var _ = func() int { +L: + switch x.(type) { + case int: + print(2) + panic(3) + break L + default: + return 4 + } +} // ERROR "missing return" + +var _ = func() int { + switch x.(type) { + default: + return 4 + break + case int: + print(2) + panic(3) + } +} // ERROR "missing return" + +var _ = func() int { +L: + switch x.(type) { + case int: + print(2) + for { + break L + } + default: + return 4 + } +} // ERROR "missing return" + /**/