- Only accept valid if statement syntax in go/parser.
- Check AST again in go/types since it may have been modified and the
AST doesn't preclude other statements in the else branch of an if
statement.
- Removed a test from gofmt which verified that old-style if statements
permitting any statement in the else branch were correctly reformatted.
It's been years since we switched to the current syntax; no need to
support this anymore.
- Added a comment to go/printer.
Fixes #13475.
Change-Id: Id2c8fbcc68b719cd511027d0412a37266cceed6b
Reviewed-on: https://go-review.googlesource.com/17408
Reviewed-by: Russ Cox <rsc@golang.org>
+++ /dev/null
-package P
-
-func f() {
- if x {
- y
- } else {
- z
- }
-}
+++ /dev/null
-package P
-
-func f() {
- if x {
- y
- } else
- z
-}
var else_ ast.Stmt
if p.tok == token.ELSE {
p.next()
- else_ = p.parseStmt()
+ switch p.tok {
+ case token.IF:
+ else_ = p.parseIfStmt()
+ case token.LBRACE:
+ else_ = p.parseBlockStmt()
+ p.expectSemi()
+ default:
+ p.errorExpected(p.pos, "if statement or block")
+ else_ = &ast.BadStmt{From: p.pos, To: p.pos}
+ }
} else {
p.expectSemi()
}
`package p; type _ struct { ( /* ERROR "expected anonymous field" */ int) };`,
`package p; func _()(x, y, z ... /* ERROR "expected '\)', found '...'" */ int){}`,
`package p; func _()(... /* ERROR "expected type, found '...'" */ int){}`,
+
+ // issue 13475
+ `package p; func f() { if true {} else ; /* ERROR "expected if statement or block" */ }`,
+ `package p; func f() { if true {} else defer /* ERROR "expected if statement or block" */ f() }`,
}
func TestInvalid(t *testing.T) {
case *ast.BlockStmt, *ast.IfStmt:
p.stmt(s.Else, nextIsRBrace)
default:
+ // This can only happen with an incorrectly
+ // constructed AST. Permit it but print so
+ // that it can be parsed without errors.
p.print(token.LBRACE, indent, formfeed)
p.stmt(s.Else, true)
p.print(unindent, formfeed, token.RBRACE)
check.error(s.Cond.Pos(), "non-boolean condition in if statement")
}
check.stmt(inner, s.Body)
- if s.Else != nil {
+ // The parser produces a correct AST but if it was modified
+ // elsewhere the else branch may be invalid. Check again.
+ switch s.Else.(type) {
+ case nil, *ast.BadStmt:
+ // valid or error already reported
+ case *ast.IfStmt, *ast.BlockStmt:
check.stmt(inner, s.Else)
+ default:
+ check.error(s.Else.Pos(), "invalid else branch in if statement")
}
case *ast.SwitchStmt: