Commit 5b3f29a2 authored by Robert Griesemer's avatar Robert Griesemer

go/parser: comma is not permitted at the end of a struct field list

Fixes #11611.

Change-Id: I63d35cf15c3be759c899e3e561e631330dcc0bbb
Reviewed-on: https://go-review.googlesource.com/14565
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarChris Manghane <cmang@golang.org>
parent 5512ac27
...@@ -695,16 +695,19 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field { ...@@ -695,16 +695,19 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
doc := p.leadComment doc := p.leadComment
// FieldDecl // 1st FieldDecl
list, typ := p.parseVarList(false) // A type name used as an anonymous field looks like a field identifier.
var list []ast.Expr
// Tag for {
var tag *ast.BasicLit list = append(list, p.parseVarType(false))
if p.tok == token.STRING { if p.tok != token.COMMA {
tag = &ast.BasicLit{ValuePos: p.pos, Kind: p.tok, Value: p.lit} break
}
p.next() p.next()
} }
typ := p.tryVarType(false)
// analyze case // analyze case
var idents []*ast.Ident var idents []*ast.Ident
if typ != nil { if typ != nil {
...@@ -713,13 +716,22 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field { ...@@ -713,13 +716,22 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
} else { } else {
// ["*"] TypeName (AnonymousField) // ["*"] TypeName (AnonymousField)
typ = list[0] // we always have at least one element typ = list[0] // we always have at least one element
if n := len(list); n > 1 || !isTypeName(deref(typ)) { if n := len(list); n > 1 {
pos := typ.Pos() p.errorExpected(p.pos, "type")
p.errorExpected(pos, "anonymous field") typ = &ast.BadExpr{From: p.pos, To: p.pos}
typ = &ast.BadExpr{From: pos, To: p.safePos(list[n-1].End())} } else if !isTypeName(deref(typ)) {
p.errorExpected(typ.Pos(), "anonymous field")
typ = &ast.BadExpr{From: typ.Pos(), To: p.safePos(typ.End())}
} }
} }
// Tag
var tag *ast.BasicLit
if p.tok == token.STRING {
tag = &ast.BasicLit{ValuePos: p.pos, Kind: p.tok, Value: p.lit}
p.next()
}
p.expectSemi() // call before accessing p.linecomment p.expectSemi() // call before accessing p.linecomment
field := &ast.Field{Doc: doc, Names: idents, Type: typ, Tag: tag, Comment: p.lineComment} field := &ast.Field{Doc: doc, Names: idents, Type: typ, Tag: tag, Comment: p.lineComment}
...@@ -796,42 +808,27 @@ func (p *parser) parseVarType(isParam bool) ast.Expr { ...@@ -796,42 +808,27 @@ func (p *parser) parseVarType(isParam bool) ast.Expr {
return typ return typ
} }
// If any of the results are identifiers, they are not resolved. func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) {
func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
if p.trace { if p.trace {
defer un(trace(p, "VarList")) defer un(trace(p, "ParameterList"))
} }
// a list of identifiers looks like a list of type names // 1st ParameterDecl
// // A list of identifiers looks like a list of type names.
// parse/tryVarType accepts any type (including parenthesized var list []ast.Expr
// ones) even though the syntax does not permit them here: we for {
// accept them all for more robust parsing and complain later list = append(list, p.parseVarType(ellipsisOk))
for typ := p.parseVarType(isParam); typ != nil; {
list = append(list, typ)
if p.tok != token.COMMA { if p.tok != token.COMMA {
break break
} }
p.next() p.next()
typ = p.tryVarType(isParam) // maybe nil as in: func f(int,) {} if p.tok == token.RPAREN {
} break
}
// if we had a list of identifiers, it must be followed by a type
typ = p.tryVarType(isParam)
return
}
func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) {
if p.trace {
defer un(trace(p, "ParameterList"))
} }
// ParameterDecl
list, typ := p.parseVarList(ellipsisOk)
// analyze case // analyze case
if typ != nil { if typ := p.tryVarType(ellipsisOk); typ != nil {
// IdentifierList Type // IdentifierList Type
idents := p.makeIdentList(list) idents := p.makeIdentList(list)
field := &ast.Field{Names: idents, Type: typ} field := &ast.Field{Names: idents, Type: typ}
......
...@@ -101,13 +101,26 @@ var invalids = []string{ ...@@ -101,13 +101,26 @@ var invalids = []string{
`package p; func f() { defer func() {} /* ERROR HERE "function must be invoked" */ }`, `package p; func f() { defer func() {} /* ERROR HERE "function must be invoked" */ }`,
`package p; func f() { go func() { func() { f(x func /* ERROR "missing ','" */ (){}) } } }`, `package p; func f() { go func() { func() { f(x func /* ERROR "missing ','" */ (){}) } } }`,
`package p; func f(x func(), u v func /* ERROR "missing ','" */ ()){}`, `package p; func f(x func(), u v func /* ERROR "missing ','" */ ()){}`,
`package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`, // issue 8656
`package p; var x /* ERROR "missing variable type or initialization" */ , y, z;`, // issue 9639 // issue 8656
`package p; const x /* ERROR "missing constant value" */ ;`, // issue 9639 `package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`,
`package p; const x /* ERROR "missing constant value" */ int;`, // issue 9639
`package p; const (x = 0; y; z /* ERROR "missing constant value" */ int);`, // issue 9639 // issue 9639
`package p; var _ = struct { x int, /* ERROR "expected ';', found ','" */ }{}`, // issue 12437 `package p; var x /* ERROR "missing variable type or initialization" */ , y, z;`,
`package p; var _ = struct { x int, /* ERROR "expected ';', found ','" */ y float }{}`, // issue 12437 `package p; const x /* ERROR "missing constant value" */ ;`,
`package p; const x /* ERROR "missing constant value" */ int;`,
`package p; const (x = 0; y; z /* ERROR "missing constant value" */ int);`,
// issue 12437
`package p; var _ = struct { x int, /* ERROR "expected ';', found ','" */ }{};`,
`package p; var _ = struct { x int, /* ERROR "expected ';', found ','" */ y float }{};`,
// issue 11611
`package p; type _ struct { int, } /* ERROR "expected type, found '}'" */ ;`,
`package p; type _ struct { int, float } /* ERROR "expected type, found '}'" */ ;`,
`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){}`,
} }
func TestInvalid(t *testing.T) { func TestInvalid(t *testing.T) {
......
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