Commit d1272a8b authored by Robert Griesemer's avatar Robert Griesemer

go/types: better error message for invalid fallthrough case

Now matches the gc compiler.

Fixes #15594.

Change-Id: I9f3942367bc0acf883c6216b8ca44820832f5fe3
Reviewed-on: https://go-review.googlesource.com/27241
TryBot-Result: Gobot Gobot <gobot@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: default avatarMatthew Dempsky <mdempsky@google.com>
parent 0c819b65
...@@ -68,13 +68,19 @@ func (check *Checker) usage(scope *Scope) { ...@@ -68,13 +68,19 @@ func (check *Checker) usage(scope *Scope) {
} }
// stmtContext is a bitset describing which // 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 type stmtContext uint
const ( const (
// permissible control-flow statements
breakOk stmtContext = 1 << iota breakOk stmtContext = 1 << iota
continueOk continueOk
fallthroughOk fallthroughOk
// additional context information
finalSwitchCase
) )
func (check *Checker) simpleStmt(s ast.Stmt) { func (check *Checker) simpleStmt(s ast.Stmt) {
...@@ -292,7 +298,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { ...@@ -292,7 +298,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
}(check.scope) }(check.scope)
} }
inner := ctxt &^ fallthroughOk inner := ctxt &^ (fallthroughOk | finalSwitchCase)
switch s := s.(type) { switch s := s.(type) {
case *ast.BadStmt, *ast.EmptyStmt: case *ast.BadStmt, *ast.EmptyStmt:
// ignore // ignore
...@@ -454,7 +460,11 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { ...@@ -454,7 +460,11 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
} }
case token.FALLTHROUGH: case token.FALLTHROUGH:
if ctxt&fallthroughOk == 0 { 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: default:
check.invalidAST(s.Pos(), "branch statement: %s", s.Tok) check.invalidAST(s.Pos(), "branch statement: %s", s.Tok)
...@@ -523,6 +533,8 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { ...@@ -523,6 +533,8 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
inner := inner inner := inner
if i+1 < len(s.Body.List) { if i+1 < len(s.Body.List) {
inner |= fallthroughOk inner |= fallthroughOk
} else {
inner |= finalSwitchCase
} }
check.stmtList(inner, clause.Body) check.stmtList(inner, clause.Body)
check.closeScope() check.closeScope()
......
...@@ -536,7 +536,7 @@ func switches1() { ...@@ -536,7 +536,7 @@ func switches1() {
default: default:
fallthrough; ; fallthrough; ;
case 4: case 4:
fallthrough /* ERROR "fallthrough statement out of place" */ fallthrough /* ERROR "cannot fallthrough final case in switch" */
} }
var y interface{} var y interface{}
...@@ -573,7 +573,7 @@ func switches1() { ...@@ -573,7 +573,7 @@ func switches1() {
goto L6 goto L6
goto L7 goto L7
goto L8 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 { switch x {
...@@ -589,6 +589,14 @@ func switches1() { ...@@ -589,6 +589,14 @@ func switches1() {
fallthrough /* ERROR "fallthrough statement out of place" */ fallthrough /* ERROR "fallthrough statement out of place" */
{ /* empty block is not an empty statement */ }; ; { /* empty block is not an empty statement */ }; ;
default: default:
fallthrough /* ERROR "cannot fallthrough final case in switch" */
}
switch x {
case 0:
{
fallthrough /* ERROR "fallthrough statement out of place" */
}
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment