go/types: don't permit declarations in post statements

Plus better names for some internal objects.

Fixes golang/go#8804.

LGTM=adonovan
R=adonovan
CC=golang-codereviews
https://golang.org/cl/149080043
This commit is contained in:
Robert Griesemer 2014-09-25 21:36:45 -07:00
parent 29d9ef959c
commit 6f764e19fa
2 changed files with 32 additions and 18 deletions

View File

@ -64,17 +64,17 @@ func (check *Checker) usage(scope *Scope) {
} }
} }
// stmtContext is a bitset describing the environment // stmtContext is a bitset describing which
// (outer statements) containing a statement. // control-flow statements are permissible.
type stmtContext uint type stmtContext uint
const ( const (
fallthroughOk stmtContext = 1 << iota breakOk stmtContext = 1 << iota
inBreakable continueOk
inContinuable fallthroughOk
) )
func (check *Checker) initStmt(s ast.Stmt) { func (check *Checker) simpleStmt(s ast.Stmt) {
if s != nil { if s != nil {
check.stmt(0, s) check.stmt(0, s)
} }
@ -351,11 +351,11 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
} }
switch s.Tok { switch s.Tok {
case token.BREAK: case token.BREAK:
if ctxt&inBreakable == 0 { if ctxt&breakOk == 0 {
check.error(s.Pos(), "break not in for, switch, or select statement") check.error(s.Pos(), "break not in for, switch, or select statement")
} }
case token.CONTINUE: case token.CONTINUE:
if ctxt&inContinuable == 0 { if ctxt&continueOk == 0 {
check.error(s.Pos(), "continue not in for statement") check.error(s.Pos(), "continue not in for statement")
} }
case token.FALLTHROUGH: case token.FALLTHROUGH:
@ -376,7 +376,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
check.openScope(s, "if") check.openScope(s, "if")
defer check.closeScope() defer check.closeScope()
check.initStmt(s.Init) check.simpleStmt(s.Init)
var x operand var x operand
check.expr(&x, s.Cond) check.expr(&x, s.Cond)
if x.mode != invalid && !isBoolean(x.typ) { if x.mode != invalid && !isBoolean(x.typ) {
@ -388,11 +388,11 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
} }
case *ast.SwitchStmt: case *ast.SwitchStmt:
inner |= inBreakable inner |= breakOk
check.openScope(s, "switch") check.openScope(s, "switch")
defer check.closeScope() defer check.closeScope()
check.initStmt(s.Init) check.simpleStmt(s.Init)
var x operand var x operand
if s.Tag != nil { if s.Tag != nil {
check.expr(&x, s.Tag) check.expr(&x, s.Tag)
@ -426,11 +426,11 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
} }
case *ast.TypeSwitchStmt: case *ast.TypeSwitchStmt:
inner |= inBreakable inner |= breakOk
check.openScope(s, "type switch") check.openScope(s, "type switch")
defer check.closeScope() defer check.closeScope()
check.initStmt(s.Init) check.simpleStmt(s.Init)
// A type switch guard must be of the form: // A type switch guard must be of the form:
// //
@ -532,7 +532,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
} }
case *ast.SelectStmt: case *ast.SelectStmt:
inner |= inBreakable inner |= breakOk
check.multipleDefaults(s.Body.List) check.multipleDefaults(s.Body.List)
@ -577,11 +577,11 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
} }
case *ast.ForStmt: case *ast.ForStmt:
inner |= inBreakable | inContinuable inner |= breakOk | continueOk
check.openScope(s, "for") check.openScope(s, "for")
defer check.closeScope() defer check.closeScope()
check.initStmt(s.Init) check.simpleStmt(s.Init)
if s.Cond != nil { if s.Cond != nil {
var x operand var x operand
check.expr(&x, s.Cond) check.expr(&x, s.Cond)
@ -589,11 +589,17 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
check.error(s.Cond.Pos(), "non-boolean condition in for statement") check.error(s.Cond.Pos(), "non-boolean condition in for statement")
} }
} }
check.initStmt(s.Post) check.simpleStmt(s.Post)
// spec: "The init statement may be a short variable
// declaration, but the post statement must not."
if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
check.softErrorf(s.Pos(), "cannot declare in post statement")
check.use(s.Lhs...) // avoid follow-up errors
}
check.stmt(inner, s.Body) check.stmt(inner, s.Body)
case *ast.RangeStmt: case *ast.RangeStmt:
inner |= inBreakable | inContinuable inner |= breakOk | continueOk
check.openScope(s, "for") check.openScope(s, "for")
defer check.closeScope() defer check.closeScope()

View File

@ -622,6 +622,14 @@ func typeswitch3(x interface{}) {
} }
} }
func fors1() {
for {}
var i string
_ = i
for i := 0; i < 10; i++ {}
for i := 0; i < 10; j /* ERROR cannot declare */ := 0 {}
}
func rangeloops1() { func rangeloops1() {
var ( var (
x int x int