From f8ae30c4a201dbdb6652cbb72cd51762863c7447 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 22 Feb 2017 13:43:23 -0800 Subject: [PATCH] cmd/compile/internal/parser: improved a couple of error messages The new syntax tree introduced with 1.8 represents send statements (ch <- x) as statements; the old syntax tree represented them as expressions (and parsed them as such) but complained if they were used in expression context. As a consequence, some of the errors that in the past were of the form "ch <- x used as value" now look like "unexpected <- ..." because a "<-" is not valid according to Go syntax in those situations. Accept the new error message. Also: Fine-tune handling of misformed for loop headers. Also: Minor cleanups/better comments. Fixes #17590. Change-Id: Ia541dea1f2f015c1b21f5b3ae44aacdec60a8aba Reviewed-on: https://go-review.googlesource.com/37386 Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/syntax/parser.go | 24 +++++++++++------------ test/syntax/chan1.go | 4 ++-- test/syntax/semi4.go | 9 ++------- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index 585765e556..d57e02bfe0 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -663,7 +663,7 @@ func (p *parser) operand(keep_parens bool) Expr { pos := p.pos() p.next() p.xnest++ - x := p.expr() // expr_or_type + x := p.expr() p.xnest-- p.want(_Rparen) @@ -719,12 +719,6 @@ func (p *parser) operand(keep_parens bool) Expr { case _Lbrack, _Chan, _Map, _Struct, _Interface: return p.type_() // othertype - case _Lbrace: - // common case: p.header is missing simpleStmt before { in if, for, switch - p.syntax_error("missing operand") - // '{' will be consumed in pexpr - no need to consume it here - return nil - default: p.syntax_error("expecting expression") p.advance() @@ -850,12 +844,12 @@ loop: // operand may have returned a parenthesized complit // type; accept it but complain if we have a complit t := unparen(x) - // determine if '{' belongs to a complit or a compound_stmt + // determine if '{' belongs to a composite literal or a block statement complit_ok := false switch t.(type) { case *Name, *SelectorExpr: if p.xnest >= 0 { - // x is considered a comptype + // x is considered a composite literal type complit_ok = true } case *ArrayType, *SliceType, *StructType, *MapType: @@ -1692,6 +1686,7 @@ func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleS } return } + // p.tok != _Lbrace outer := p.xnest p.xnest = -1 @@ -1712,7 +1707,7 @@ func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleS var condStmt SimpleStmt var semi struct { pos src.Pos - lit string + lit string // valid if pos.IsKnown() } if p.tok == _Semi { semi.pos = p.pos() @@ -1720,6 +1715,10 @@ func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleS p.next() if keyword == _For { if p.tok != _Semi { + if p.tok == _Lbrace { + p.syntax_error("expecting for loop condition") + goto done + } condStmt = p.simpleStmt(nil, false) } p.want(_Semi) @@ -1734,10 +1733,11 @@ func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleS init = nil } +done: // unpack condStmt switch s := condStmt.(type) { case nil: - if keyword == _If { + if keyword == _If && semi.pos.IsKnown() { if semi.lit != "semicolon" { p.syntax_error_at(semi.pos, fmt.Sprintf("unexpected %s, expecting { after if clause", semi.lit)) } else { @@ -2037,7 +2037,7 @@ func (p *parser) call(fun Expr) *CallExpr { p.xnest++ for p.tok != _EOF && p.tok != _Rparen { - c.ArgList = append(c.ArgList, p.expr()) // expr_or_type + c.ArgList = append(c.ArgList, p.expr()) c.HasDots = p.got(_DotDotDot) if !p.ocomma(_Rparen) || c.HasDots { break diff --git a/test/syntax/chan1.go b/test/syntax/chan1.go index a33a0d4cea..4eb63796ac 100644 --- a/test/syntax/chan1.go +++ b/test/syntax/chan1.go @@ -10,8 +10,8 @@ var c chan int var v int func main() { - if c <- v { // ERROR "used as value|missing condition|invalid condition" + if c <- v { // ERROR "used as value" } } -var _ = c <- v // ERROR "used as value|unexpected <-" +var _ = c <- v // ERROR "unexpected <-" diff --git a/test/syntax/semi4.go b/test/syntax/semi4.go index 0b5e677680..f21431b3f5 100644 --- a/test/syntax/semi4.go +++ b/test/syntax/semi4.go @@ -4,14 +4,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// TODO(mdempsky): Update error expectations for new parser. -// The new parser emits an extra "missing { after for clause" error. -// The old parser is supposed to emit this too, but it panics first -// due to a nil pointer dereference. - package main func main() { for x // GCCGO_ERROR "undefined" - { // ERROR "expecting .*{.* after for clause|missing operand" - z // ERROR "undefined|expecting { after for clause" + { // ERROR "unexpected {, expecting for loop condition" + z -- 2.50.0