]> Cypherpunks repositories - gostls13.git/commitdiff
go/parser: comma is not permitted at the end of a struct field list
authorRobert Griesemer <gri@golang.org>
Mon, 14 Sep 2015 23:30:37 +0000 (16:30 -0700)
committerRobert Griesemer <gri@golang.org>
Wed, 16 Sep 2015 20:06:01 +0000 (20:06 +0000)
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>
src/go/parser/parser.go
src/go/parser/short_test.go

index 855caa3daa4a96e7700c90208cc613fcfe78f8ed..521bdce1ddf0eed3b3d9377adb74752de3e4b53e 100644 (file)
@@ -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) {
+func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) {
        if p.trace {
-               defer un(trace(p, "VarList"))
+               defer un(trace(p, "ParameterList"))
        }
 
-       // 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)
+       // 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()
-               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"))
+               if p.tok == token.RPAREN {
+                       break
+               }
        }
 
-       // ParameterDecl
-       list, typ := p.parseVarList(ellipsisOk)
-
        // 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}
index 7cbdaf2e24ba876bff774a7c99a34e07c86435a3..6ef3b0725595636ee2c37e014b5b815e6a0edb52 100644 (file)
@@ -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) {