mirror of
https://github.com/golang/go
synced 2024-09-04 15:34:21 +00:00
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 <cmang@golang.org>
This commit is contained in:
parent
1a111ea2c7
commit
5500d46914
|
@ -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
|
||||
|
||||
|
|
29
test/fixedbugs/issue13261.go
Normal file
29
test/fixedbugs/issue13261.go
Normal file
|
@ -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{}{})) {}
|
||||
}
|
Loading…
Reference in a new issue