}
// stmtContext is a bitset describing which
-// control-flow statements are permissible.
+// control-flow statements are permissible,
+// and provides additional context information
+// for better error messages.
type stmtContext uint
const (
+ // permissible control-flow statements
breakOk stmtContext = 1 << iota
continueOk
fallthroughOk
+
+ // additional context information
+ finalSwitchCase
)
func (check *Checker) simpleStmt(s ast.Stmt) {
}(check.scope)
}
- inner := ctxt &^ fallthroughOk
+ inner := ctxt &^ (fallthroughOk | finalSwitchCase)
switch s := s.(type) {
case *ast.BadStmt, *ast.EmptyStmt:
// ignore
}
case token.FALLTHROUGH:
if ctxt&fallthroughOk == 0 {
- check.error(s.Pos(), "fallthrough statement out of place")
+ msg := "fallthrough statement out of place"
+ if ctxt&finalSwitchCase != 0 {
+ msg = "cannot fallthrough final case in switch"
+ }
+ check.error(s.Pos(), msg)
}
default:
check.invalidAST(s.Pos(), "branch statement: %s", s.Tok)
inner := inner
if i+1 < len(s.Body.List) {
inner |= fallthroughOk
+ } else {
+ inner |= finalSwitchCase
}
check.stmtList(inner, clause.Body)
check.closeScope()
default:
fallthrough; ;
case 4:
- fallthrough /* ERROR "fallthrough statement out of place" */
+ fallthrough /* ERROR "cannot fallthrough final case in switch" */
}
var y interface{}
goto L6
goto L7
goto L8
- L6: L7: L8: fallthrough /* ERROR "fallthrough statement out of place" */
+ L6: L7: L8: fallthrough /* ERROR "cannot fallthrough final case in switch" */
}
switch x {
fallthrough /* ERROR "fallthrough statement out of place" */
{ /* empty block is not an empty statement */ }; ;
default:
+ fallthrough /* ERROR "cannot fallthrough final case in switch" */
+ }
+
+ switch x {
+ case 0:
+ {
+ fallthrough /* ERROR "fallthrough statement out of place" */
+ }
}
}