From: Robert Griesemer Date: Wed, 18 Nov 2015 18:57:27 +0000 (-0800) Subject: cmd/compile/internal/gc: fix incorrect parsing of &(T{}) when followed by { X-Git-Tag: go1.6beta1~390 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=5500d46914baf26e164ba6dae22ccd343556b5ab;p=gostls13.git cmd/compile/internal/gc: fix incorrect parsing of &(T{}) when followed by { Handling of &(T{}) assumed that the parser would not introduce ()'s. Also: Better comments around handling of OPAREN syntax tree optimization. Fixes #13261. Change-Id: Ifc5047a0448f5e7d74cd42f6608b87dcc9c2f2fb Reviewed-on: https://go-review.googlesource.com/17040 Reviewed-by: Chris Manghane --- diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index bb2799d2e4..a3ecf92c08 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -1276,6 +1276,13 @@ func (p *parser) expr() *Node { return p.bexpr(1) } +func unparen(x *Node) *Node { + for x.Op == OPAREN { + x = x.Left + } + return x +} + // go.y:uexpr func (p *parser) uexpr() *Node { if trace && Debug['x'] != 0 { @@ -1289,7 +1296,9 @@ func (p *parser) uexpr() *Node { case '&': p.next() - x := p.uexpr() + // uexpr may have returned a parenthesized composite literal + // (see comment in operand) - remove parentheses if any + x := unparen(p.uexpr()) if x.Op == OCOMPLIT { // Special case for &T{...}: turn into (*T){...}. x.Right = Nod(OIND, x.Right, nil) @@ -1349,6 +1358,7 @@ func (p *parser) uexpr() *Node { // t is type <-chan E but <-<-chan E is not permitted // (report same error as for "type _ <-<-chan E") p.syntax_error("unexpected <-, expecting chan") + // already progressed, no need to advance } t.Etype = Crecv } @@ -1356,6 +1366,7 @@ func (p *parser) uexpr() *Node { // channel dir is <- but channel element E is not a channel // (report same error as for "type _ <-chan<-E") p.syntax_error(fmt.Sprintf("unexpected %v, expecting chan", t)) + // already progressed, no need to advance } return x } @@ -1380,7 +1391,9 @@ func (p *parser) pseudocall() *Node { defer p.trace("pseudocall")() } - x := p.pexpr(true) + // The expression in go/defer must not be parenthesized; + // don't drop ()'s so we can report an error. + x := p.pexpr(true /* keep_parens */) if x.Op != OCALL { Yyerror("argument to go/defer must be function call") } @@ -1409,25 +1422,29 @@ func (p *parser) operand(keep_parens bool) *Node { p.nest-- p.want(')') - // Need to know on lhs of := whether there are ( ). - // Don't bother with the OPAREN in other cases: - // it's just a waste of memory and time. - // - // But if the next token is a { , introduce OPAREN since - // we may have a composite literal and we need to know - // if there were ()'s'. - // - // TODO(gri) could simplify this if we parse complits - // in operand (see respective comment in pexpr). - // - // (We can probably not do this because of qualified types - // as in pkg.Type{}) (issue 13243). - if keep_parens || p.tok == '{' { - return Nod(OPAREN, x, nil) - } + // Optimization: Record presence of ()'s only where needed + // for error reporting. Don't bother in other cases; it is + // just a waste of memory and time. + + // Parentheses are not permitted on lhs of := . switch x.Op { case ONAME, ONONAME, OPACK, OTYPE, OLITERAL, OTYPESW: - return Nod(OPAREN, x, nil) + keep_parens = true + } + + // Parentheses are not permitted around T in a composite + // literal T{}. If the next token is a {, assume x is a + // composite literal type T (it may not be, { could be + // the opening brace of a block, but we don't know yet). + if p.tok == '{' { + keep_parens = true + } + + // Parentheses are also not permitted around the expression + // in a go/defer statement. In that case, operand is called + // with keep_parens set. + if keep_parens { + x = Nod(OPAREN, x, nil) } return x diff --git a/test/fixedbugs/issue13261.go b/test/fixedbugs/issue13261.go new file mode 100644 index 0000000000..c73062c6ca --- /dev/null +++ b/test/fixedbugs/issue13261.go @@ -0,0 +1,29 @@ +// compile + +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Taking the address of a parenthesized composite literal is permitted. + +package main + +type T struct{} + +func main() { + _ = &T{} + _ = &(T{}) + _ = &((T{})) + + _ = &struct{}{} + _ = &(struct{}{}) + _ = &((struct{}{})) + + switch (&T{}) {} + switch &(T{}) {} + switch &((T{})) {} + + switch &struct{}{} {} + switch &(struct{}{}) {} + switch &((struct{}{})) {} +}