From: Robert Griesemer Date: Thu, 18 Aug 2022 03:11:57 +0000 (-0700) Subject: go/parser: disallow parenthesizing embedded types in structs X-Git-Tag: go1.20rc1~1512 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=9b48ffa98af149408b8e4734676bcc2cf95278fd;p=gostls13.git go/parser: disallow parenthesizing embedded types in structs This was never permitted in Go but the flexibility to do so was introduced through the generics prototype code where we experimented with parentheses to enclose type parameters. Restore original (pre-generics) behavior. Fixes #51655. Change-Id: Ia7a4b2e393e0214a70e840c8663cf4474c5c754b Reviewed-on: https://go-review.googlesource.com/c/go/+/424694 Run-TryBot: Robert Griesemer Reviewed-by: Robert Griesemer Reviewed-by: Robert Findley TryBot-Result: Gopher Robot --- diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index d4ad36dc67..acb71ee9ac 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -643,7 +643,8 @@ func (p *parser) parseFieldDecl() *ast.Field { var names []*ast.Ident var typ ast.Expr - if p.tok == token.IDENT { + switch p.tok { + case token.IDENT: name := p.parseIdent() if p.tok == token.PERIOD || p.tok == token.STRING || p.tok == token.SEMICOLON || p.tok == token.RBRACE { // embedded type @@ -670,11 +671,46 @@ func (p *parser) parseFieldDecl() *ast.Field { typ = p.parseType() } } - } else { - // embedded, possibly generic type - // (using the enclosing parentheses to distinguish it from a named field declaration) - // TODO(rFindley) confirm that this doesn't allow parenthesized embedded type - typ = p.parseType() + case token.MUL: + star := p.pos + p.next() + if p.tok == token.LPAREN { + // *(T) + p.error(p.pos, "cannot parenthesize embedded type") + p.next() + typ = p.parseQualifiedIdent(nil) + // expect closing ')' but no need to complain if missing + if p.tok == token.RPAREN { + p.next() + } + } else { + // *T + typ = p.parseQualifiedIdent(nil) + } + typ = &ast.StarExpr{Star: star, X: typ} + + case token.LPAREN: + p.error(p.pos, "cannot parenthesize embedded type") + p.next() + if p.tok == token.MUL { + // (*T) + star := p.pos + p.next() + typ = &ast.StarExpr{Star: star, X: p.parseQualifiedIdent(nil)} + } else { + // (T) + typ = p.parseQualifiedIdent(nil) + } + // expect closing ')' but no need to complain if missing + if p.tok == token.RPAREN { + p.next() + } + + default: + pos := p.pos + p.errorExpected(pos, "field name or embedded type") + p.advance(exprEnd) + typ = &ast.BadExpr{From: pos, To: p.pos} } var tag *ast.BasicLit diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go index d117f0d381..be8be6450c 100644 --- a/src/go/parser/short_test.go +++ b/src/go/parser/short_test.go @@ -52,9 +52,9 @@ var valids = []string{ `package p; type T = int`, `package p; type (T = p.T; _ = struct{}; x = *T)`, `package p; type T (*int)`, - `package p; type _ struct{ ((int)) }`, - `package p; type _ struct{ (*(int)) }`, - `package p; type _ struct{ ([]byte) }`, // disallowed by type-checker + `package p; type _ struct{ int }`, + `package p; type _ struct{ pkg.T }`, + `package p; type _ struct{ *pkg.T }`, `package p; var _ = func()T(nil)`, `package p; func _(T (P))`, `package p; func _(T []E)`, @@ -195,6 +195,12 @@ var invalids = []string{ `package p; func (type /* ERROR "found 'type'" */ T)(T) _()`, `package p; type _[A+B, /* ERROR "unexpected comma" */ ] int`, + `package p; type _ struct{ [ /* ERROR "expected '}', found '\['" */ ]byte }`, + `package p; type _ struct{ ( /* ERROR "cannot parenthesize embedded type" */ int) }`, + `package p; type _ struct{ ( /* ERROR "cannot parenthesize embedded type" */ []byte) }`, + `package p; type _ struct{ *( /* ERROR "cannot parenthesize embedded type" */ int) }`, + `package p; type _ struct{ *( /* ERROR "cannot parenthesize embedded type" */ []byte) }`, + // TODO(rfindley): this error should be positioned on the ':' `package p; var a = a[[]int:[ /* ERROR "expected expression" */ ]int];`,