Skip to content

Commit f823d30

Browse files
committed
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/36930 Reviewed-by: Matthew Dempsky <[email protected]>
1 parent 02de5ed commit f823d30

File tree

2 files changed

+55
-15
lines changed

2 files changed

+55
-15
lines changed

src/cmd/compile/internal/syntax/parser.go

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1662,7 +1662,7 @@ func (p *parser) forStmt() Stmt {
16621662
s.init(p)
16631663

16641664
p.want(_For)
1665-
s.Init, s.Cond, s.Post = p.header(true)
1665+
s.Init, s.Cond, s.Post = p.header(_For)
16661666
if gcCompat {
16671667
s.init(p)
16681668
}
@@ -1688,10 +1688,13 @@ func (p *parser) stmtBody(context string) []Stmt {
16881688
return body
16891689
}
16901690

1691-
var dummyCond = &Name{Value: "false"}
1691+
func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleStmt) {
1692+
// TODO(gri) move caller's p.want(keyword) here, once we removed gcCompat
16921693

1693-
func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleStmt) {
16941694
if p.tok == _Lbrace {
1695+
if keyword == _If {
1696+
p.syntax_error("missing condition in if statement")
1697+
}
16951698
return
16961699
}
16971700

@@ -1700,20 +1703,27 @@ func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleSt
17001703

17011704
if p.tok != _Semi {
17021705
// accept potential varDecl but complain
1703-
if forStmt && p.got(_Var) {
1706+
if keyword == _For && p.got(_Var) {
17041707
p.syntax_error("var declaration not allowed in for initializer")
17051708
}
1706-
init = p.simpleStmt(nil, forStmt)
1707-
// If we have a range clause, we are done.
1709+
init = p.simpleStmt(nil, keyword == _For)
1710+
// If we have a range clause, we are done (can only happen for keyword == _For).
17081711
if _, ok := init.(*RangeClause); ok {
17091712
p.xnest = outer
17101713
return
17111714
}
17121715
}
17131716

17141717
var condStmt SimpleStmt
1715-
if p.got(_Semi) {
1716-
if forStmt {
1718+
var semi struct {
1719+
pos src.Pos
1720+
lit string
1721+
}
1722+
if p.tok == _Semi {
1723+
semi.pos = p.pos()
1724+
semi.lit = p.lit
1725+
p.next()
1726+
if keyword == _For {
17171727
if p.tok != _Semi {
17181728
condStmt = p.simpleStmt(nil, false)
17191729
}
@@ -1732,12 +1742,17 @@ func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleSt
17321742
// unpack condStmt
17331743
switch s := condStmt.(type) {
17341744
case nil:
1735-
// nothing to do
1745+
if keyword == _If {
1746+
if semi.lit != "semicolon" {
1747+
p.syntax_error_at(semi.pos, fmt.Sprintf("unexpected %s, expecting { after if clause", semi.lit))
1748+
} else {
1749+
p.syntax_error_at(semi.pos, "missing condition in if statement")
1750+
}
1751+
}
17361752
case *ExprStmt:
17371753
cond = s.X
17381754
default:
17391755
p.syntax_error(fmt.Sprintf("%s used as value", String(s)))
1740-
cond = dummyCond // avoid follow-up error for if statements
17411756
}
17421757

17431758
p.xnest = outer
@@ -1753,10 +1768,7 @@ func (p *parser) ifStmt() *IfStmt {
17531768
s.init(p)
17541769

17551770
p.want(_If)
1756-
s.Init, s.Cond, _ = p.header(false)
1757-
if s.Cond == nil {
1758-
p.syntax_error("missing condition in if statement")
1759-
}
1771+
s.Init, s.Cond, _ = p.header(_If)
17601772

17611773
if gcCompat {
17621774
s.init(p)
@@ -1788,7 +1800,7 @@ func (p *parser) switchStmt() *SwitchStmt {
17881800
s := new(SwitchStmt)
17891801
s.init(p)
17901802

1791-
s.Init, s.Tag, _ = p.header(false)
1803+
s.Init, s.Tag, _ = p.header(_Switch)
17921804

17931805
if !p.got(_Lbrace) {
17941806
p.syntax_error("missing { after switch clause")

test/fixedbugs/issue18747.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// errorcheck
2+
3+
// Copyright 2017 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package p
8+
9+
func _ () {
10+
if {} // ERROR "missing condition in if statement"
11+
12+
if
13+
{} // ERROR "missing condition in if statement"
14+
15+
if ; {} // ERROR "missing condition in if statement"
16+
17+
if foo; {} // ERROR "missing condition in if statement"
18+
19+
if foo; // ERROR "missing condition in if statement"
20+
{}
21+
22+
if foo {}
23+
24+
if ; foo {}
25+
26+
if foo // ERROR "unexpected newline, expecting { after if clause"
27+
{}
28+
}

0 commit comments

Comments
 (0)