mirror of
https://github.com/golang/go
synced 2024-11-18 00:54:45 -07:00
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: Chris Manghane <cmang@golang.org>
This commit is contained in:
parent
5512ac2786
commit
5b3f29a2e7
@ -695,16 +695,19 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
|
||||
|
||||
doc := p.leadComment
|
||||
|
||||
// FieldDecl
|
||||
list, typ := p.parseVarList(false)
|
||||
|
||||
// Tag
|
||||
var tag *ast.BasicLit
|
||||
if p.tok == token.STRING {
|
||||
tag = &ast.BasicLit{ValuePos: p.pos, Kind: p.tok, Value: p.lit}
|
||||
// 1st FieldDecl
|
||||
// A type name used as an anonymous field looks like a field identifier.
|
||||
var list []ast.Expr
|
||||
for {
|
||||
list = append(list, p.parseVarType(false))
|
||||
if p.tok != token.COMMA {
|
||||
break
|
||||
}
|
||||
p.next()
|
||||
}
|
||||
|
||||
typ := p.tryVarType(false)
|
||||
|
||||
// analyze case
|
||||
var idents []*ast.Ident
|
||||
if typ != nil {
|
||||
@ -713,13 +716,22 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
|
||||
} else {
|
||||
// ["*"] TypeName (AnonymousField)
|
||||
typ = list[0] // we always have at least one element
|
||||
if n := len(list); n > 1 || !isTypeName(deref(typ)) {
|
||||
pos := typ.Pos()
|
||||
p.errorExpected(pos, "anonymous field")
|
||||
typ = &ast.BadExpr{From: pos, To: p.safePos(list[n-1].End())}
|
||||
if n := len(list); n > 1 {
|
||||
p.errorExpected(p.pos, "type")
|
||||
typ = &ast.BadExpr{From: p.pos, To: p.pos}
|
||||
} 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
|
||||
|
||||
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 {
|
||||
return typ
|
||||
}
|
||||
|
||||
// If any of the results are identifiers, they are not resolved.
|
||||
func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
|
||||
if p.trace {
|
||||
defer un(trace(p, "VarList"))
|
||||
}
|
||||
|
||||
// a list of identifiers looks like a list of type names
|
||||
//
|
||||
// parse/tryVarType accepts any type (including parenthesized
|
||||
// ones) even though the syntax does not permit them here: we
|
||||
// accept them all for more robust parsing and complain later
|
||||
for typ := p.parseVarType(isParam); typ != nil; {
|
||||
list = append(list, typ)
|
||||
if p.tok != token.COMMA {
|
||||
break
|
||||
}
|
||||
p.next()
|
||||
typ = p.tryVarType(isParam) // maybe nil as in: func f(int,) {}
|
||||
}
|
||||
|
||||
// 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)
|
||||
// 1st ParameterDecl
|
||||
// A list of identifiers looks like a list of type names.
|
||||
var list []ast.Expr
|
||||
for {
|
||||
list = append(list, p.parseVarType(ellipsisOk))
|
||||
if p.tok != token.COMMA {
|
||||
break
|
||||
}
|
||||
p.next()
|
||||
if p.tok == token.RPAREN {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// analyze case
|
||||
if typ != nil {
|
||||
if typ := p.tryVarType(ellipsisOk); typ != nil {
|
||||
// IdentifierList Type
|
||||
idents := p.makeIdentList(list)
|
||||
field := &ast.Field{Names: idents, Type: typ}
|
||||
|
@ -101,13 +101,26 @@ var invalids = []string{
|
||||
`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(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
|
||||
`package p; const x /* ERROR "missing constant value" */ ;`, // issue 9639
|
||||
`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
|
||||
`package p; var _ = struct { x int, /* ERROR "expected ';', found ','" */ }{}`, // issue 12437
|
||||
`package p; var _ = struct { x int, /* ERROR "expected ';', found ','" */ y float }{}`, // issue 12437
|
||||
|
||||
// issue 8656
|
||||
`package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`,
|
||||
|
||||
// issue 9639
|
||||
`package p; var x /* ERROR "missing variable type or initialization" */ , y, z;`,
|
||||
`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) {
|
||||
|
Loading…
Reference in New Issue
Block a user