mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +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
2 changed files with 65 additions and 19 deletions
|
|
@ -1276,6 +1276,13 @@ func (p *parser) expr() *Node {
|
||||||
return p.bexpr(1)
|
return p.bexpr(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unparen(x *Node) *Node {
|
||||||
|
for x.Op == OPAREN {
|
||||||
|
x = x.Left
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
// go.y:uexpr
|
// go.y:uexpr
|
||||||
func (p *parser) uexpr() *Node {
|
func (p *parser) uexpr() *Node {
|
||||||
if trace && Debug['x'] != 0 {
|
if trace && Debug['x'] != 0 {
|
||||||
|
|
@ -1289,7 +1296,9 @@ func (p *parser) uexpr() *Node {
|
||||||
|
|
||||||
case '&':
|
case '&':
|
||||||
p.next()
|
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 {
|
if x.Op == OCOMPLIT {
|
||||||
// Special case for &T{...}: turn into (*T){...}.
|
// Special case for &T{...}: turn into (*T){...}.
|
||||||
x.Right = Nod(OIND, x.Right, nil)
|
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
|
// t is type <-chan E but <-<-chan E is not permitted
|
||||||
// (report same error as for "type _ <-<-chan E")
|
// (report same error as for "type _ <-<-chan E")
|
||||||
p.syntax_error("unexpected <-, expecting chan")
|
p.syntax_error("unexpected <-, expecting chan")
|
||||||
|
// already progressed, no need to advance
|
||||||
}
|
}
|
||||||
t.Etype = Crecv
|
t.Etype = Crecv
|
||||||
}
|
}
|
||||||
|
|
@ -1356,6 +1366,7 @@ func (p *parser) uexpr() *Node {
|
||||||
// channel dir is <- but channel element E is not a channel
|
// channel dir is <- but channel element E is not a channel
|
||||||
// (report same error as for "type _ <-chan<-E")
|
// (report same error as for "type _ <-chan<-E")
|
||||||
p.syntax_error(fmt.Sprintf("unexpected %v, expecting chan", t))
|
p.syntax_error(fmt.Sprintf("unexpected %v, expecting chan", t))
|
||||||
|
// already progressed, no need to advance
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
@ -1380,7 +1391,9 @@ func (p *parser) pseudocall() *Node {
|
||||||
defer p.trace("pseudocall")()
|
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 {
|
if x.Op != OCALL {
|
||||||
Yyerror("argument to go/defer must be function call")
|
Yyerror("argument to go/defer must be function call")
|
||||||
}
|
}
|
||||||
|
|
@ -1409,25 +1422,29 @@ func (p *parser) operand(keep_parens bool) *Node {
|
||||||
p.nest--
|
p.nest--
|
||||||
p.want(')')
|
p.want(')')
|
||||||
|
|
||||||
// Need to know on lhs of := whether there are ( ).
|
// Optimization: Record presence of ()'s only where needed
|
||||||
// Don't bother with the OPAREN in other cases:
|
// for error reporting. Don't bother in other cases; it is
|
||||||
// it's just a waste of memory and time.
|
// just a waste of memory and time.
|
||||||
//
|
|
||||||
// But if the next token is a { , introduce OPAREN since
|
// Parentheses are not permitted on lhs of := .
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
switch x.Op {
|
switch x.Op {
|
||||||
case ONAME, ONONAME, OPACK, OTYPE, OLITERAL, OTYPESW:
|
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
|
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…
Add table
Add a link
Reference in a new issue