Commit f823d305 authored by Robert Griesemer's avatar Robert Griesemer

cmd/compile/internal/syntax: better error for malformed 'if' statements

Use distinction between explicit and automatically inserted semicolons
to provide a better error message if the condition in an 'if' statement
is missing.

For #18747.

Change-Id: Iac167ae4e5ad53d2dc73f746b4dee9912434bb59
Reviewed-on: https://go-review.googlesource.com/36930Reviewed-by: 's avatarMatthew Dempsky <mdempsky@google.com>
parent 02de5ed7
...@@ -1662,7 +1662,7 @@ func (p *parser) forStmt() Stmt { ...@@ -1662,7 +1662,7 @@ func (p *parser) forStmt() Stmt {
s.init(p) s.init(p)
p.want(_For) p.want(_For)
s.Init, s.Cond, s.Post = p.header(true) s.Init, s.Cond, s.Post = p.header(_For)
if gcCompat { if gcCompat {
s.init(p) s.init(p)
} }
...@@ -1688,10 +1688,13 @@ func (p *parser) stmtBody(context string) []Stmt { ...@@ -1688,10 +1688,13 @@ func (p *parser) stmtBody(context string) []Stmt {
return body return body
} }
var dummyCond = &Name{Value: "false"} func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleStmt) {
// TODO(gri) move caller's p.want(keyword) here, once we removed gcCompat
func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleStmt) {
if p.tok == _Lbrace { if p.tok == _Lbrace {
if keyword == _If {
p.syntax_error("missing condition in if statement")
}
return return
} }
...@@ -1700,11 +1703,11 @@ func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleSt ...@@ -1700,11 +1703,11 @@ func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleSt
if p.tok != _Semi { if p.tok != _Semi {
// accept potential varDecl but complain // accept potential varDecl but complain
if forStmt && p.got(_Var) { if keyword == _For && p.got(_Var) {
p.syntax_error("var declaration not allowed in for initializer") p.syntax_error("var declaration not allowed in for initializer")
} }
init = p.simpleStmt(nil, forStmt) init = p.simpleStmt(nil, keyword == _For)
// If we have a range clause, we are done. // If we have a range clause, we are done (can only happen for keyword == _For).
if _, ok := init.(*RangeClause); ok { if _, ok := init.(*RangeClause); ok {
p.xnest = outer p.xnest = outer
return return
...@@ -1712,8 +1715,15 @@ func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleSt ...@@ -1712,8 +1715,15 @@ func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleSt
} }
var condStmt SimpleStmt var condStmt SimpleStmt
if p.got(_Semi) { var semi struct {
if forStmt { pos src.Pos
lit string
}
if p.tok == _Semi {
semi.pos = p.pos()
semi.lit = p.lit
p.next()
if keyword == _For {
if p.tok != _Semi { if p.tok != _Semi {
condStmt = p.simpleStmt(nil, false) condStmt = p.simpleStmt(nil, false)
} }
...@@ -1732,12 +1742,17 @@ func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleSt ...@@ -1732,12 +1742,17 @@ func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleSt
// unpack condStmt // unpack condStmt
switch s := condStmt.(type) { switch s := condStmt.(type) {
case nil: case nil:
// nothing to do if keyword == _If {
if semi.lit != "semicolon" {
p.syntax_error_at(semi.pos, fmt.Sprintf("unexpected %s, expecting { after if clause", semi.lit))
} else {
p.syntax_error_at(semi.pos, "missing condition in if statement")
}
}
case *ExprStmt: case *ExprStmt:
cond = s.X cond = s.X
default: default:
p.syntax_error(fmt.Sprintf("%s used as value", String(s))) p.syntax_error(fmt.Sprintf("%s used as value", String(s)))
cond = dummyCond // avoid follow-up error for if statements
} }
p.xnest = outer p.xnest = outer
...@@ -1753,10 +1768,7 @@ func (p *parser) ifStmt() *IfStmt { ...@@ -1753,10 +1768,7 @@ func (p *parser) ifStmt() *IfStmt {
s.init(p) s.init(p)
p.want(_If) p.want(_If)
s.Init, s.Cond, _ = p.header(false) s.Init, s.Cond, _ = p.header(_If)
if s.Cond == nil {
p.syntax_error("missing condition in if statement")
}
if gcCompat { if gcCompat {
s.init(p) s.init(p)
...@@ -1788,7 +1800,7 @@ func (p *parser) switchStmt() *SwitchStmt { ...@@ -1788,7 +1800,7 @@ func (p *parser) switchStmt() *SwitchStmt {
s := new(SwitchStmt) s := new(SwitchStmt)
s.init(p) s.init(p)
s.Init, s.Tag, _ = p.header(false) s.Init, s.Tag, _ = p.header(_Switch)
if !p.got(_Lbrace) { if !p.got(_Lbrace) {
p.syntax_error("missing { after switch clause") p.syntax_error("missing { after switch clause")
......
// errorcheck
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
func _ () {
if {} // ERROR "missing condition in if statement"
if
{} // ERROR "missing condition in if statement"
if ; {} // ERROR "missing condition in if statement"
if foo; {} // ERROR "missing condition in if statement"
if foo; // ERROR "missing condition in if statement"
{}
if foo {}
if ; foo {}
if foo // ERROR "unexpected newline, expecting { after if clause"
{}
}
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