mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.regabi] cmd/compile: clean up in preparation for statement Nodes
Using statement nodes restricts the set of valid SetOp operations,
because you can't SetOp across representation. Rewrite various
code to avoid crossing those as-yet-unintroduced boundaries.
In particular, code like
x, y := v.(T)
x, y := f()
x, y := m[k]
x, y := <-c
starts out with Op = OAS2, and then it turns into a specific Op
OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV, and then
later in walk is lowered to an OAS2 again.
In the middle, the specific forms move the right-hand side from
n.Rlist().First() to n.Right(), and then the conversion to OAS2 moves
it back. This is unnecessary and makes it hard for these all to
share an underlying Node implementation.
This CL changes these specific forms to leave the right-hand side
in n.Rlist().First().
Similarly, OSELRECV2 is really just a temporary form of OAS2.
This CL changes it to use same fields too.
Finally, this CL fixes the printing of OAS2 nodes in ir/fmt.go,
which formerly printed n.Right() instead of n.Rlist().
This results in a (correct!) update to cmd/compile/internal/logopt's
expected output: ~R0 = <N> becomes ~R0 = &y.b.
Passes buildall w/ toolstash -cmp.
Change-Id: I164aa2e17dc55bfb292024de53d7d250192ad64a
Reviewed-on: https://go-review.googlesource.com/c/go/+/274105
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
c6de5d8d1f
commit
7c9b6b1ca2
15 changed files with 243 additions and 269 deletions
|
|
@ -394,8 +394,8 @@ func (e *Escape) stmt(n ir.Node) {
|
||||||
case ir.OSELRECV:
|
case ir.OSELRECV:
|
||||||
e.assign(n.Left(), n.Right(), "selrecv", n)
|
e.assign(n.Left(), n.Right(), "selrecv", n)
|
||||||
case ir.OSELRECV2:
|
case ir.OSELRECV2:
|
||||||
e.assign(n.Left(), n.Right(), "selrecv", n)
|
e.assign(n.List().First(), n.Rlist().First(), "selrecv", n)
|
||||||
e.assign(n.List().First(), nil, "selrecv", n)
|
e.assign(n.List().Second(), nil, "selrecv", n)
|
||||||
case ir.ORECV:
|
case ir.ORECV:
|
||||||
// TODO(mdempsky): Consider e.discard(n.Left).
|
// TODO(mdempsky): Consider e.discard(n.Left).
|
||||||
e.exprSkipInit(e.discardHole(), n) // already visited n.Ninit
|
e.exprSkipInit(e.discardHole(), n) // already visited n.Ninit
|
||||||
|
|
@ -412,18 +412,18 @@ func (e *Escape) stmt(n ir.Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case ir.OAS2DOTTYPE: // v, ok = x.(type)
|
case ir.OAS2DOTTYPE: // v, ok = x.(type)
|
||||||
e.assign(n.List().First(), n.Right(), "assign-pair-dot-type", n)
|
e.assign(n.List().First(), n.Rlist().First(), "assign-pair-dot-type", n)
|
||||||
e.assign(n.List().Second(), nil, "assign-pair-dot-type", n)
|
e.assign(n.List().Second(), nil, "assign-pair-dot-type", n)
|
||||||
case ir.OAS2MAPR: // v, ok = m[k]
|
case ir.OAS2MAPR: // v, ok = m[k]
|
||||||
e.assign(n.List().First(), n.Right(), "assign-pair-mapr", n)
|
e.assign(n.List().First(), n.Rlist().First(), "assign-pair-mapr", n)
|
||||||
e.assign(n.List().Second(), nil, "assign-pair-mapr", n)
|
e.assign(n.List().Second(), nil, "assign-pair-mapr", n)
|
||||||
case ir.OAS2RECV: // v, ok = <-ch
|
case ir.OAS2RECV: // v, ok = <-ch
|
||||||
e.assign(n.List().First(), n.Right(), "assign-pair-receive", n)
|
e.assign(n.List().First(), n.Rlist().First(), "assign-pair-receive", n)
|
||||||
e.assign(n.List().Second(), nil, "assign-pair-receive", n)
|
e.assign(n.List().Second(), nil, "assign-pair-receive", n)
|
||||||
|
|
||||||
case ir.OAS2FUNC:
|
case ir.OAS2FUNC:
|
||||||
e.stmts(n.Right().Init())
|
e.stmts(n.Rlist().First().Init())
|
||||||
e.call(e.addrs(n.List()), n.Right(), nil)
|
e.call(e.addrs(n.List()), n.Rlist().First(), nil)
|
||||||
case ir.ORETURN:
|
case ir.ORETURN:
|
||||||
results := e.curfn.Type().Results().FieldSlice()
|
results := e.curfn.Type().Results().FieldSlice()
|
||||||
for i, v := range n.List().Slice() {
|
for i, v := range n.List().Slice() {
|
||||||
|
|
@ -709,8 +709,7 @@ func (e *Escape) discards(l ir.Nodes) {
|
||||||
// that represents storing into the represented location.
|
// that represents storing into the represented location.
|
||||||
func (e *Escape) addr(n ir.Node) EscHole {
|
func (e *Escape) addr(n ir.Node) EscHole {
|
||||||
if n == nil || ir.IsBlank(n) {
|
if n == nil || ir.IsBlank(n) {
|
||||||
// Can happen at least in OSELRECV.
|
// Can happen in select case, range, maybe others.
|
||||||
// TODO(mdempsky): Anywhere else?
|
|
||||||
return e.discardHole()
|
return e.discardHole()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1076,18 +1076,12 @@ func (w *exportWriter) stmt(n ir.Node) {
|
||||||
w.expr(n.Right())
|
w.expr(n.Right())
|
||||||
}
|
}
|
||||||
|
|
||||||
case ir.OAS2:
|
case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
|
||||||
w.op(ir.OAS2)
|
w.op(ir.OAS2)
|
||||||
w.pos(n.Pos())
|
w.pos(n.Pos())
|
||||||
w.exprList(n.List())
|
w.exprList(n.List())
|
||||||
w.exprList(n.Rlist())
|
w.exprList(n.Rlist())
|
||||||
|
|
||||||
case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
|
|
||||||
w.op(ir.OAS2)
|
|
||||||
w.pos(n.Pos())
|
|
||||||
w.exprList(n.List())
|
|
||||||
w.exprList(ir.AsNodes([]ir.Node{n.Right()}))
|
|
||||||
|
|
||||||
case ir.ORETURN:
|
case ir.ORETURN:
|
||||||
w.op(ir.ORETURN)
|
w.op(ir.ORETURN)
|
||||||
w.pos(n.Pos())
|
w.pos(n.Pos())
|
||||||
|
|
|
||||||
|
|
@ -256,7 +256,7 @@ func collectDeps(n ir.Node, transitive bool) ir.NodeSet {
|
||||||
case ir.OAS:
|
case ir.OAS:
|
||||||
d.inspect(n.Right())
|
d.inspect(n.Right())
|
||||||
case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
|
case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
|
||||||
d.inspect(n.Right())
|
d.inspect(n.Rlist().First())
|
||||||
case ir.ODCLFUNC:
|
case ir.ODCLFUNC:
|
||||||
d.inspectList(n.Body())
|
d.inspectList(n.Body())
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -520,14 +520,11 @@ func inlcalls(fn *ir.Func) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn an OINLCALL into a statement.
|
// Turn an OINLCALL into a statement.
|
||||||
func inlconv2stmt(n ir.Node) {
|
func inlconv2stmt(inlcall ir.Node) ir.Node {
|
||||||
n.SetOp(ir.OBLOCK)
|
n := ir.NodAt(inlcall.Pos(), ir.OBLOCK, nil, nil)
|
||||||
|
n.SetList(inlcall.Body())
|
||||||
// n->ninit stays
|
n.SetInit(inlcall.Init())
|
||||||
n.PtrList().Set(n.Body().Slice())
|
return n
|
||||||
|
|
||||||
n.PtrBody().Set(nil)
|
|
||||||
n.PtrRlist().Set(nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn an OINLCALL into a single valued expression.
|
// Turn an OINLCALL into a single valued expression.
|
||||||
|
|
@ -600,9 +597,10 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool) ir.Node {
|
||||||
lno := setlineno(n)
|
lno := setlineno(n)
|
||||||
|
|
||||||
inlnodelist(n.Init(), maxCost, inlMap)
|
inlnodelist(n.Init(), maxCost, inlMap)
|
||||||
for _, n1 := range n.Init().Slice() {
|
init := n.Init().Slice()
|
||||||
|
for i, n1 := range init {
|
||||||
if n1.Op() == ir.OINLCALL {
|
if n1.Op() == ir.OINLCALL {
|
||||||
inlconv2stmt(n1)
|
init[i] = inlconv2stmt(n1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -614,50 +612,49 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool) ir.Node {
|
||||||
n.SetRight(inlnode(n.Right(), maxCost, inlMap))
|
n.SetRight(inlnode(n.Right(), maxCost, inlMap))
|
||||||
if n.Right() != nil && n.Right().Op() == ir.OINLCALL {
|
if n.Right() != nil && n.Right().Op() == ir.OINLCALL {
|
||||||
if n.Op() == ir.OFOR || n.Op() == ir.OFORUNTIL {
|
if n.Op() == ir.OFOR || n.Op() == ir.OFORUNTIL {
|
||||||
inlconv2stmt(n.Right())
|
n.SetRight(inlconv2stmt(n.Right()))
|
||||||
} else if n.Op() == ir.OAS2FUNC {
|
|
||||||
n.PtrRlist().Set(inlconv2list(n.Right()))
|
|
||||||
n.SetRight(nil)
|
|
||||||
n.SetOp(ir.OAS2)
|
|
||||||
n.SetTypecheck(0)
|
|
||||||
n = typecheck(n, ctxStmt)
|
|
||||||
} else {
|
} else {
|
||||||
n.SetRight(inlconv2expr(n.Right()))
|
n.SetRight(inlconv2expr(n.Right()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inlnodelist(n.List(), maxCost, inlMap)
|
inlnodelist(n.List(), maxCost, inlMap)
|
||||||
|
s := n.List().Slice()
|
||||||
|
convert := inlconv2expr
|
||||||
if n.Op() == ir.OBLOCK {
|
if n.Op() == ir.OBLOCK {
|
||||||
for _, n2 := range n.List().Slice() {
|
convert = inlconv2stmt
|
||||||
if n2.Op() == ir.OINLCALL {
|
}
|
||||||
inlconv2stmt(n2)
|
for i, n1 := range s {
|
||||||
}
|
if n1 != nil && n1.Op() == ir.OINLCALL {
|
||||||
}
|
s[i] = convert(n1)
|
||||||
} else {
|
|
||||||
s := n.List().Slice()
|
|
||||||
for i1, n1 := range s {
|
|
||||||
if n1 != nil && n1.Op() == ir.OINLCALL {
|
|
||||||
s[i1] = inlconv2expr(s[i1])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inlnodelist(n.Rlist(), maxCost, inlMap)
|
inlnodelist(n.Rlist(), maxCost, inlMap)
|
||||||
s := n.Rlist().Slice()
|
|
||||||
for i1, n1 := range s {
|
if n.Op() == ir.OAS2FUNC && n.Rlist().First().Op() == ir.OINLCALL {
|
||||||
|
n.PtrRlist().Set(inlconv2list(n.Rlist().First()))
|
||||||
|
n.SetOp(ir.OAS2)
|
||||||
|
n.SetTypecheck(0)
|
||||||
|
n = typecheck(n, ctxStmt)
|
||||||
|
}
|
||||||
|
|
||||||
|
s = n.Rlist().Slice()
|
||||||
|
for i, n1 := range s {
|
||||||
if n1.Op() == ir.OINLCALL {
|
if n1.Op() == ir.OINLCALL {
|
||||||
if n.Op() == ir.OIF {
|
if n.Op() == ir.OIF {
|
||||||
inlconv2stmt(n1)
|
s[i] = inlconv2stmt(n1)
|
||||||
} else {
|
} else {
|
||||||
s[i1] = inlconv2expr(s[i1])
|
s[i] = inlconv2expr(n1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inlnodelist(n.Body(), maxCost, inlMap)
|
inlnodelist(n.Body(), maxCost, inlMap)
|
||||||
for _, n := range n.Body().Slice() {
|
s = n.Body().Slice()
|
||||||
if n.Op() == ir.OINLCALL {
|
for i, n1 := range s {
|
||||||
inlconv2stmt(n)
|
if n1.Op() == ir.OINLCALL {
|
||||||
|
s[i] = inlconv2stmt(n1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1200,9 +1197,10 @@ func mkinlcall(n ir.Node, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]bool)
|
||||||
// and each use must redo the inlining.
|
// and each use must redo the inlining.
|
||||||
// luckily these are small.
|
// luckily these are small.
|
||||||
inlnodelist(call.Body(), maxCost, inlMap)
|
inlnodelist(call.Body(), maxCost, inlMap)
|
||||||
for _, n := range call.Body().Slice() {
|
s := call.Body().Slice()
|
||||||
if n.Op() == ir.OINLCALL {
|
for i, n1 := range s {
|
||||||
inlconv2stmt(n)
|
if n1.Op() == ir.OINLCALL {
|
||||||
|
s[i] = inlconv2stmt(n1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1001,20 +1001,17 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) ir.Node {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
n := p.nod(stmt, ir.OAS, nil, nil) // assume common case
|
|
||||||
|
|
||||||
rhs := p.exprList(stmt.Rhs)
|
rhs := p.exprList(stmt.Rhs)
|
||||||
lhs := p.assignList(stmt.Lhs, n, stmt.Op == syntax.Def)
|
if list, ok := stmt.Lhs.(*syntax.ListExpr); ok && len(list.ElemList) != 1 || len(rhs) != 1 {
|
||||||
|
n := p.nod(stmt, ir.OAS2, nil, nil)
|
||||||
if len(lhs) == 1 && len(rhs) == 1 {
|
n.PtrList().Set(p.assignList(stmt.Lhs, n, stmt.Op == syntax.Def))
|
||||||
// common case
|
|
||||||
n.SetLeft(lhs[0])
|
|
||||||
n.SetRight(rhs[0])
|
|
||||||
} else {
|
|
||||||
n.SetOp(ir.OAS2)
|
|
||||||
n.PtrList().Set(lhs)
|
|
||||||
n.PtrRlist().Set(rhs)
|
n.PtrRlist().Set(rhs)
|
||||||
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n := p.nod(stmt, ir.OAS, nil, nil)
|
||||||
|
n.SetLeft(p.assignList(stmt.Lhs, n, stmt.Op == syntax.Def)[0])
|
||||||
|
n.SetRight(rhs[0])
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case *syntax.BranchStmt:
|
case *syntax.BranchStmt:
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,11 @@ func (o *Order) newTemp(t *types.Type, clear bool) ir.Node {
|
||||||
// (The other candidate would be map access, but map access
|
// (The other candidate would be map access, but map access
|
||||||
// returns a pointer to the result data instead of taking a pointer
|
// returns a pointer to the result data instead of taking a pointer
|
||||||
// to be filled in.)
|
// to be filled in.)
|
||||||
|
// TODO(rsc): t == n.Type() always; remove parameter.
|
||||||
func (o *Order) copyExpr(n ir.Node, t *types.Type, clear bool) ir.Node {
|
func (o *Order) copyExpr(n ir.Node, t *types.Type, clear bool) ir.Node {
|
||||||
|
if t != n.Type() {
|
||||||
|
panic("copyExpr")
|
||||||
|
}
|
||||||
v := o.newTemp(t, clear)
|
v := o.newTemp(t, clear)
|
||||||
a := ir.Nod(ir.OAS, v, n)
|
a := ir.Nod(ir.OAS, v, n)
|
||||||
a = typecheck(a, ctxStmt)
|
a = typecheck(a, ctxStmt)
|
||||||
|
|
@ -606,23 +610,19 @@ func (o *Order) stmt(n ir.Node) {
|
||||||
// that we can ensure that if op panics
|
// that we can ensure that if op panics
|
||||||
// because r is zero, the panic happens before
|
// because r is zero, the panic happens before
|
||||||
// the map assignment.
|
// the map assignment.
|
||||||
|
// DeepCopy is a big hammer here, but safeExpr
|
||||||
n.SetLeft(o.safeExpr(n.Left()))
|
// makes sure there is nothing too deep being copied.
|
||||||
|
l1 := o.safeExpr(n.Left())
|
||||||
// TODO(rsc): Why is this DeepCopy?
|
l2 := ir.DeepCopy(src.NoXPos, l1)
|
||||||
// We should know enough about the form here
|
if l1.Op() == ir.OINDEXMAP {
|
||||||
// to do something more provably shallower.
|
l2.SetIndexMapLValue(false)
|
||||||
l := ir.DeepCopy(src.NoXPos, n.Left())
|
|
||||||
if l.Op() == ir.OINDEXMAP {
|
|
||||||
l.SetIndexMapLValue(false)
|
|
||||||
}
|
}
|
||||||
l = o.copyExpr(l, n.Left().Type(), false)
|
l2 = o.copyExpr(l2, l2.Type(), false)
|
||||||
n.SetRight(ir.Nod(n.SubOp(), l, n.Right()))
|
r := ir.NodAt(n.Pos(), n.SubOp(), l2, n.Right())
|
||||||
n.SetRight(typecheck(n.Right(), ctxExpr))
|
r = typecheck(r, ctxExpr)
|
||||||
n.SetRight(o.expr(n.Right(), nil))
|
r = o.expr(r, nil)
|
||||||
|
n = ir.NodAt(n.Pos(), ir.OAS, l1, r)
|
||||||
n.SetOp(ir.OAS)
|
n = typecheck(n, ctxStmt)
|
||||||
n.ResetAux()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
o.mapAssign(n)
|
o.mapAssign(n)
|
||||||
|
|
@ -639,8 +639,8 @@ func (o *Order) stmt(n ir.Node) {
|
||||||
case ir.OAS2FUNC:
|
case ir.OAS2FUNC:
|
||||||
t := o.markTemp()
|
t := o.markTemp()
|
||||||
o.exprList(n.List())
|
o.exprList(n.List())
|
||||||
o.init(n.Right())
|
o.init(n.Rlist().First())
|
||||||
o.call(n.Right())
|
o.call(n.Rlist().First())
|
||||||
o.as2(n)
|
o.as2(n)
|
||||||
o.cleanTemp(t)
|
o.cleanTemp(t)
|
||||||
|
|
||||||
|
|
@ -654,7 +654,7 @@ func (o *Order) stmt(n ir.Node) {
|
||||||
t := o.markTemp()
|
t := o.markTemp()
|
||||||
o.exprList(n.List())
|
o.exprList(n.List())
|
||||||
|
|
||||||
switch r := n.Right(); r.Op() {
|
switch r := n.Rlist().First(); r.Op() {
|
||||||
case ir.ODOTTYPE2, ir.ORECV:
|
case ir.ODOTTYPE2, ir.ORECV:
|
||||||
r.SetLeft(o.expr(r.Left(), nil))
|
r.SetLeft(o.expr(r.Left(), nil))
|
||||||
case ir.OINDEXMAP:
|
case ir.OINDEXMAP:
|
||||||
|
|
@ -866,38 +866,39 @@ func (o *Order) stmt(n ir.Node) {
|
||||||
ir.Dump("select case", r)
|
ir.Dump("select case", r)
|
||||||
base.Fatalf("unknown op in select %v", r.Op())
|
base.Fatalf("unknown op in select %v", r.Op())
|
||||||
|
|
||||||
// If this is case x := <-ch or case x, y := <-ch, the case has
|
|
||||||
// the ODCL nodes to declare x and y. We want to delay that
|
|
||||||
// declaration (and possible allocation) until inside the case body.
|
|
||||||
// Delete the ODCL nodes here and recreate them inside the body below.
|
|
||||||
case ir.OSELRECV, ir.OSELRECV2:
|
case ir.OSELRECV, ir.OSELRECV2:
|
||||||
if r.Colas() {
|
var dst, ok, recv ir.Node
|
||||||
i := 0
|
if r.Op() == ir.OSELRECV {
|
||||||
if r.Init().Len() != 0 && r.Init().First().Op() == ir.ODCL && r.Init().First().Left() == r.Left() {
|
// case x = <-c
|
||||||
i++
|
// case <-c (dst is ir.BlankNode)
|
||||||
}
|
dst, ok, recv = r.Left(), ir.BlankNode, r.Right()
|
||||||
if i < r.Init().Len() && r.Init().Index(i).Op() == ir.ODCL && r.List().Len() != 0 && r.Init().Index(i).Left() == r.List().First() {
|
} else {
|
||||||
i++
|
// case x, ok = <-c
|
||||||
}
|
dst, ok, recv = r.List().First(), r.List().Second(), r.Rlist().First()
|
||||||
if i >= r.Init().Len() {
|
|
||||||
r.PtrInit().Set(nil)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is case x := <-ch or case x, y := <-ch, the case has
|
||||||
|
// the ODCL nodes to declare x and y. We want to delay that
|
||||||
|
// declaration (and possible allocation) until inside the case body.
|
||||||
|
// Delete the ODCL nodes here and recreate them inside the body below.
|
||||||
|
if r.Colas() {
|
||||||
|
init := r.Init().Slice()
|
||||||
|
if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].Left() == dst {
|
||||||
|
init = init[1:]
|
||||||
|
}
|
||||||
|
if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].Left() == ok {
|
||||||
|
init = init[1:]
|
||||||
|
}
|
||||||
|
r.PtrInit().Set(init)
|
||||||
|
}
|
||||||
if r.Init().Len() != 0 {
|
if r.Init().Len() != 0 {
|
||||||
ir.DumpList("ninit", r.Init())
|
ir.DumpList("ninit", r.Init())
|
||||||
base.Fatalf("ninit on select recv")
|
base.Fatalf("ninit on select recv")
|
||||||
}
|
}
|
||||||
|
|
||||||
// case x = <-c
|
recv.SetLeft(o.expr(recv.Left(), nil))
|
||||||
// case x, ok = <-c
|
if recv.Left().Op() != ir.ONAME {
|
||||||
// r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c.
|
recv.SetLeft(o.copyExpr(recv.Left(), recv.Left().Type(), false))
|
||||||
// r->left == N means 'case <-c'.
|
|
||||||
// c is always evaluated; x and ok are only evaluated when assigned.
|
|
||||||
r.Right().SetLeft(o.expr(r.Right().Left(), nil))
|
|
||||||
|
|
||||||
if r.Right().Left().Op() != ir.ONAME {
|
|
||||||
r.Right().SetLeft(o.copyExpr(r.Right().Left(), r.Right().Left().Type(), false))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Introduce temporary for receive and move actual copy into case body.
|
// Introduce temporary for receive and move actual copy into case body.
|
||||||
|
|
@ -906,42 +907,41 @@ func (o *Order) stmt(n ir.Node) {
|
||||||
// temporary per distinct type, sharing the temp among all receives
|
// temporary per distinct type, sharing the temp among all receives
|
||||||
// with that temp. Similarly one ok bool could be shared among all
|
// with that temp. Similarly one ok bool could be shared among all
|
||||||
// the x,ok receives. Not worth doing until there's a clear need.
|
// the x,ok receives. Not worth doing until there's a clear need.
|
||||||
if r.Left() != nil && ir.IsBlank(r.Left()) {
|
if !ir.IsBlank(dst) {
|
||||||
r.SetLeft(nil)
|
|
||||||
}
|
|
||||||
if r.Left() != nil {
|
|
||||||
// use channel element type for temporary to avoid conversions,
|
// use channel element type for temporary to avoid conversions,
|
||||||
// such as in case interfacevalue = <-intchan.
|
// such as in case interfacevalue = <-intchan.
|
||||||
// the conversion happens in the OAS instead.
|
// the conversion happens in the OAS instead.
|
||||||
tmp1 := r.Left()
|
|
||||||
|
|
||||||
if r.Colas() {
|
if r.Colas() {
|
||||||
tmp2 := ir.Nod(ir.ODCL, tmp1, nil)
|
dcl := ir.Nod(ir.ODCL, dst, nil)
|
||||||
tmp2 = typecheck(tmp2, ctxStmt)
|
dcl = typecheck(dcl, ctxStmt)
|
||||||
n2.PtrInit().Append(tmp2)
|
n2.PtrInit().Append(dcl)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.SetLeft(o.newTemp(r.Right().Left().Type().Elem(), r.Right().Left().Type().Elem().HasPointers()))
|
tmp := o.newTemp(recv.Left().Type().Elem(), recv.Left().Type().Elem().HasPointers())
|
||||||
tmp2 := ir.Nod(ir.OAS, tmp1, r.Left())
|
as := ir.Nod(ir.OAS, dst, tmp)
|
||||||
tmp2 = typecheck(tmp2, ctxStmt)
|
as = typecheck(as, ctxStmt)
|
||||||
n2.PtrInit().Append(tmp2)
|
n2.PtrInit().Append(as)
|
||||||
|
dst = tmp
|
||||||
}
|
}
|
||||||
|
if !ir.IsBlank(ok) {
|
||||||
if r.List().Len() != 0 && ir.IsBlank(r.List().First()) {
|
|
||||||
r.PtrList().Set(nil)
|
|
||||||
}
|
|
||||||
if r.List().Len() != 0 {
|
|
||||||
tmp1 := r.List().First()
|
|
||||||
if r.Colas() {
|
if r.Colas() {
|
||||||
tmp2 := ir.Nod(ir.ODCL, tmp1, nil)
|
dcl := ir.Nod(ir.ODCL, ok, nil)
|
||||||
tmp2 = typecheck(tmp2, ctxStmt)
|
dcl = typecheck(dcl, ctxStmt)
|
||||||
n2.PtrInit().Append(tmp2)
|
n2.PtrInit().Append(dcl)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.PtrList().Set1(o.newTemp(types.Types[types.TBOOL], false))
|
tmp := o.newTemp(types.Types[types.TBOOL], false)
|
||||||
tmp2 := okas(tmp1, r.List().First())
|
as := okas(ok, tmp)
|
||||||
tmp2 = typecheck(tmp2, ctxStmt)
|
as = typecheck(as, ctxStmt)
|
||||||
n2.PtrInit().Append(tmp2)
|
n2.PtrInit().Append(as)
|
||||||
|
ok = tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Op() == ir.OSELRECV {
|
||||||
|
r.SetLeft(dst)
|
||||||
|
} else {
|
||||||
|
r.List().SetIndex(0, dst)
|
||||||
|
r.List().SetIndex(1, ok)
|
||||||
}
|
}
|
||||||
orderBlock(n2.PtrInit(), o.free)
|
orderBlock(n2.PtrInit(), o.free)
|
||||||
|
|
||||||
|
|
@ -1420,7 +1420,7 @@ func (o *Order) as2(n ir.Node) {
|
||||||
func (o *Order) okAs2(n ir.Node) {
|
func (o *Order) okAs2(n ir.Node) {
|
||||||
var tmp1, tmp2 ir.Node
|
var tmp1, tmp2 ir.Node
|
||||||
if !ir.IsBlank(n.List().First()) {
|
if !ir.IsBlank(n.List().First()) {
|
||||||
typ := n.Right().Type()
|
typ := n.Rlist().First().Type()
|
||||||
tmp1 = o.newTemp(typ, typ.HasPointers())
|
tmp1 = o.newTemp(typ, typ.HasPointers())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -157,15 +157,19 @@ func cheapComputableIndex(width int64) bool {
|
||||||
// simpler forms. The result must be assigned back to n.
|
// simpler forms. The result must be assigned back to n.
|
||||||
// Node n may also be modified in place, and may also be
|
// Node n may also be modified in place, and may also be
|
||||||
// the returned node.
|
// the returned node.
|
||||||
func walkrange(n ir.Node) ir.Node {
|
func walkrange(nrange ir.Node) ir.Node {
|
||||||
if isMapClear(n) {
|
if isMapClear(nrange) {
|
||||||
m := n.Right()
|
m := nrange.Right()
|
||||||
lno := setlineno(m)
|
lno := setlineno(m)
|
||||||
n = mapClear(m)
|
n := mapClear(m)
|
||||||
base.Pos = lno
|
base.Pos = lno
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nfor := ir.NodAt(nrange.Pos(), ir.OFOR, nil, nil)
|
||||||
|
nfor.SetInit(nrange.Init())
|
||||||
|
nfor.SetSym(nrange.Sym())
|
||||||
|
|
||||||
// variable name conventions:
|
// variable name conventions:
|
||||||
// ohv1, hv1, hv2: hidden (old) val 1, 2
|
// ohv1, hv1, hv2: hidden (old) val 1, 2
|
||||||
// ha, hit: hidden aggregate, iterator
|
// ha, hit: hidden aggregate, iterator
|
||||||
|
|
@ -173,20 +177,19 @@ func walkrange(n ir.Node) ir.Node {
|
||||||
// hb: hidden bool
|
// hb: hidden bool
|
||||||
// a, v1, v2: not hidden aggregate, val 1, 2
|
// a, v1, v2: not hidden aggregate, val 1, 2
|
||||||
|
|
||||||
t := n.Type()
|
t := nrange.Type()
|
||||||
|
|
||||||
a := n.Right()
|
a := nrange.Right()
|
||||||
lno := setlineno(a)
|
lno := setlineno(a)
|
||||||
n.SetRight(nil)
|
|
||||||
|
|
||||||
var v1, v2 ir.Node
|
var v1, v2 ir.Node
|
||||||
l := n.List().Len()
|
l := nrange.List().Len()
|
||||||
if l > 0 {
|
if l > 0 {
|
||||||
v1 = n.List().First()
|
v1 = nrange.List().First()
|
||||||
}
|
}
|
||||||
|
|
||||||
if l > 1 {
|
if l > 1 {
|
||||||
v2 = n.List().Second()
|
v2 = nrange.List().Second()
|
||||||
}
|
}
|
||||||
|
|
||||||
if ir.IsBlank(v2) {
|
if ir.IsBlank(v2) {
|
||||||
|
|
@ -201,14 +204,8 @@ func walkrange(n ir.Node) ir.Node {
|
||||||
base.Fatalf("walkrange: v2 != nil while v1 == nil")
|
base.Fatalf("walkrange: v2 != nil while v1 == nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
// n.List has no meaning anymore, clear it
|
|
||||||
// to avoid erroneous processing by racewalk.
|
|
||||||
n.PtrList().Set(nil)
|
|
||||||
|
|
||||||
var ifGuard ir.Node
|
var ifGuard ir.Node
|
||||||
|
|
||||||
translatedLoopOp := ir.OFOR
|
|
||||||
|
|
||||||
var body []ir.Node
|
var body []ir.Node
|
||||||
var init []ir.Node
|
var init []ir.Node
|
||||||
switch t.Etype {
|
switch t.Etype {
|
||||||
|
|
@ -216,9 +213,9 @@ func walkrange(n ir.Node) ir.Node {
|
||||||
base.Fatalf("walkrange")
|
base.Fatalf("walkrange")
|
||||||
|
|
||||||
case types.TARRAY, types.TSLICE:
|
case types.TARRAY, types.TSLICE:
|
||||||
if arrayClear(n, v1, v2, a) {
|
if nn := arrayClear(nrange, v1, v2, a); nn != nil {
|
||||||
base.Pos = lno
|
base.Pos = lno
|
||||||
return n
|
return nn
|
||||||
}
|
}
|
||||||
|
|
||||||
// order.stmt arranged for a copy of the array/slice variable if needed.
|
// order.stmt arranged for a copy of the array/slice variable if needed.
|
||||||
|
|
@ -230,8 +227,8 @@ func walkrange(n ir.Node) ir.Node {
|
||||||
init = append(init, ir.Nod(ir.OAS, hv1, nil))
|
init = append(init, ir.Nod(ir.OAS, hv1, nil))
|
||||||
init = append(init, ir.Nod(ir.OAS, hn, ir.Nod(ir.OLEN, ha, nil)))
|
init = append(init, ir.Nod(ir.OAS, hn, ir.Nod(ir.OLEN, ha, nil)))
|
||||||
|
|
||||||
n.SetLeft(ir.Nod(ir.OLT, hv1, hn))
|
nfor.SetLeft(ir.Nod(ir.OLT, hv1, hn))
|
||||||
n.SetRight(ir.Nod(ir.OAS, hv1, ir.Nod(ir.OADD, hv1, nodintconst(1))))
|
nfor.SetRight(ir.Nod(ir.OAS, hv1, ir.Nod(ir.OADD, hv1, nodintconst(1))))
|
||||||
|
|
||||||
// for range ha { body }
|
// for range ha { body }
|
||||||
if v1 == nil {
|
if v1 == nil {
|
||||||
|
|
@ -245,7 +242,7 @@ func walkrange(n ir.Node) ir.Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
// for v1, v2 := range ha { body }
|
// for v1, v2 := range ha { body }
|
||||||
if cheapComputableIndex(n.Type().Elem().Width) {
|
if cheapComputableIndex(nrange.Type().Elem().Width) {
|
||||||
// v1, v2 = hv1, ha[hv1]
|
// v1, v2 = hv1, ha[hv1]
|
||||||
tmp := ir.Nod(ir.OINDEX, ha, hv1)
|
tmp := ir.Nod(ir.OINDEX, ha, hv1)
|
||||||
tmp.SetBounded(true)
|
tmp.SetBounded(true)
|
||||||
|
|
@ -272,9 +269,9 @@ func walkrange(n ir.Node) ir.Node {
|
||||||
// Enhance the prove pass to understand this.
|
// Enhance the prove pass to understand this.
|
||||||
ifGuard = ir.Nod(ir.OIF, nil, nil)
|
ifGuard = ir.Nod(ir.OIF, nil, nil)
|
||||||
ifGuard.SetLeft(ir.Nod(ir.OLT, hv1, hn))
|
ifGuard.SetLeft(ir.Nod(ir.OLT, hv1, hn))
|
||||||
translatedLoopOp = ir.OFORUNTIL
|
nfor.SetOp(ir.OFORUNTIL)
|
||||||
|
|
||||||
hp := temp(types.NewPtr(n.Type().Elem()))
|
hp := temp(types.NewPtr(nrange.Type().Elem()))
|
||||||
tmp := ir.Nod(ir.OINDEX, ha, nodintconst(0))
|
tmp := ir.Nod(ir.OINDEX, ha, nodintconst(0))
|
||||||
tmp.SetBounded(true)
|
tmp.SetBounded(true)
|
||||||
init = append(init, ir.Nod(ir.OAS, hp, ir.Nod(ir.OADDR, tmp, nil)))
|
init = append(init, ir.Nod(ir.OAS, hp, ir.Nod(ir.OADDR, tmp, nil)))
|
||||||
|
|
@ -293,16 +290,15 @@ func walkrange(n ir.Node) ir.Node {
|
||||||
// end of the allocation.
|
// end of the allocation.
|
||||||
a = ir.Nod(ir.OAS, hp, addptr(hp, t.Elem().Width))
|
a = ir.Nod(ir.OAS, hp, addptr(hp, t.Elem().Width))
|
||||||
a = typecheck(a, ctxStmt)
|
a = typecheck(a, ctxStmt)
|
||||||
n.PtrList().Set1(a)
|
nfor.PtrList().Set1(a)
|
||||||
|
|
||||||
case types.TMAP:
|
case types.TMAP:
|
||||||
// order.stmt allocated the iterator for us.
|
// order.stmt allocated the iterator for us.
|
||||||
// we only use a once, so no copy needed.
|
// we only use a once, so no copy needed.
|
||||||
ha := a
|
ha := a
|
||||||
|
|
||||||
hit := prealloc[n]
|
hit := prealloc[nrange]
|
||||||
th := hit.Type()
|
th := hit.Type()
|
||||||
n.SetLeft(nil)
|
|
||||||
keysym := th.Field(0).Sym // depends on layout of iterator struct. See reflect.go:hiter
|
keysym := th.Field(0).Sym // depends on layout of iterator struct. See reflect.go:hiter
|
||||||
elemsym := th.Field(1).Sym // ditto
|
elemsym := th.Field(1).Sym // ditto
|
||||||
|
|
||||||
|
|
@ -310,11 +306,11 @@ func walkrange(n ir.Node) ir.Node {
|
||||||
|
|
||||||
fn = substArgTypes(fn, t.Key(), t.Elem(), th)
|
fn = substArgTypes(fn, t.Key(), t.Elem(), th)
|
||||||
init = append(init, mkcall1(fn, nil, nil, typename(t), ha, ir.Nod(ir.OADDR, hit, nil)))
|
init = append(init, mkcall1(fn, nil, nil, typename(t), ha, ir.Nod(ir.OADDR, hit, nil)))
|
||||||
n.SetLeft(ir.Nod(ir.ONE, nodSym(ir.ODOT, hit, keysym), nodnil()))
|
nfor.SetLeft(ir.Nod(ir.ONE, nodSym(ir.ODOT, hit, keysym), nodnil()))
|
||||||
|
|
||||||
fn = syslook("mapiternext")
|
fn = syslook("mapiternext")
|
||||||
fn = substArgTypes(fn, th)
|
fn = substArgTypes(fn, th)
|
||||||
n.SetRight(mkcall1(fn, nil, nil, ir.Nod(ir.OADDR, hit, nil)))
|
nfor.SetRight(mkcall1(fn, nil, nil, ir.Nod(ir.OADDR, hit, nil)))
|
||||||
|
|
||||||
key := nodSym(ir.ODOT, hit, keysym)
|
key := nodSym(ir.ODOT, hit, keysym)
|
||||||
key = ir.Nod(ir.ODEREF, key, nil)
|
key = ir.Nod(ir.ODEREF, key, nil)
|
||||||
|
|
@ -335,8 +331,6 @@ func walkrange(n ir.Node) ir.Node {
|
||||||
// order.stmt arranged for a copy of the channel variable.
|
// order.stmt arranged for a copy of the channel variable.
|
||||||
ha := a
|
ha := a
|
||||||
|
|
||||||
n.SetLeft(nil)
|
|
||||||
|
|
||||||
hv1 := temp(t.Elem())
|
hv1 := temp(t.Elem())
|
||||||
hv1.SetTypecheck(1)
|
hv1.SetTypecheck(1)
|
||||||
if t.Elem().HasPointers() {
|
if t.Elem().HasPointers() {
|
||||||
|
|
@ -344,12 +338,12 @@ func walkrange(n ir.Node) ir.Node {
|
||||||
}
|
}
|
||||||
hb := temp(types.Types[types.TBOOL])
|
hb := temp(types.Types[types.TBOOL])
|
||||||
|
|
||||||
n.SetLeft(ir.Nod(ir.ONE, hb, nodbool(false)))
|
nfor.SetLeft(ir.Nod(ir.ONE, hb, nodbool(false)))
|
||||||
a := ir.Nod(ir.OAS2RECV, nil, nil)
|
a := ir.Nod(ir.OAS2RECV, nil, nil)
|
||||||
a.SetTypecheck(1)
|
a.SetTypecheck(1)
|
||||||
a.PtrList().Set2(hv1, hb)
|
a.PtrList().Set2(hv1, hb)
|
||||||
a.SetRight(ir.Nod(ir.ORECV, ha, nil))
|
a.PtrRlist().Set1(ir.Nod(ir.ORECV, ha, nil))
|
||||||
n.Left().PtrInit().Set1(a)
|
nfor.Left().PtrInit().Set1(a)
|
||||||
if v1 == nil {
|
if v1 == nil {
|
||||||
body = nil
|
body = nil
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -387,7 +381,7 @@ func walkrange(n ir.Node) ir.Node {
|
||||||
init = append(init, ir.Nod(ir.OAS, hv1, nil))
|
init = append(init, ir.Nod(ir.OAS, hv1, nil))
|
||||||
|
|
||||||
// hv1 < len(ha)
|
// hv1 < len(ha)
|
||||||
n.SetLeft(ir.Nod(ir.OLT, hv1, ir.Nod(ir.OLEN, ha, nil)))
|
nfor.SetLeft(ir.Nod(ir.OLT, hv1, ir.Nod(ir.OLEN, ha, nil)))
|
||||||
|
|
||||||
if v1 != nil {
|
if v1 != nil {
|
||||||
// hv1t = hv1
|
// hv1t = hv1
|
||||||
|
|
@ -431,24 +425,25 @@ func walkrange(n ir.Node) ir.Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n.SetOp(translatedLoopOp)
|
|
||||||
typecheckslice(init, ctxStmt)
|
typecheckslice(init, ctxStmt)
|
||||||
|
|
||||||
if ifGuard != nil {
|
if ifGuard != nil {
|
||||||
ifGuard.PtrInit().Append(init...)
|
ifGuard.PtrInit().Append(init...)
|
||||||
ifGuard = typecheck(ifGuard, ctxStmt)
|
ifGuard = typecheck(ifGuard, ctxStmt)
|
||||||
} else {
|
} else {
|
||||||
n.PtrInit().Append(init...)
|
nfor.PtrInit().Append(init...)
|
||||||
}
|
}
|
||||||
|
|
||||||
typecheckslice(n.Left().Init().Slice(), ctxStmt)
|
typecheckslice(nfor.Left().Init().Slice(), ctxStmt)
|
||||||
|
|
||||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
nfor.SetLeft(typecheck(nfor.Left(), ctxExpr))
|
||||||
n.SetLeft(defaultlit(n.Left(), nil))
|
nfor.SetLeft(defaultlit(nfor.Left(), nil))
|
||||||
n.SetRight(typecheck(n.Right(), ctxStmt))
|
nfor.SetRight(typecheck(nfor.Right(), ctxStmt))
|
||||||
typecheckslice(body, ctxStmt)
|
typecheckslice(body, ctxStmt)
|
||||||
n.PtrBody().Prepend(body...)
|
nfor.PtrBody().Append(body...)
|
||||||
|
nfor.PtrBody().Append(nrange.Body().Slice()...)
|
||||||
|
|
||||||
|
var n ir.Node = nfor
|
||||||
if ifGuard != nil {
|
if ifGuard != nil {
|
||||||
ifGuard.PtrBody().Set1(n)
|
ifGuard.PtrBody().Set1(n)
|
||||||
n = ifGuard
|
n = ifGuard
|
||||||
|
|
@ -534,31 +529,31 @@ func mapClear(m ir.Node) ir.Node {
|
||||||
// in which the evaluation of a is side-effect-free.
|
// in which the evaluation of a is side-effect-free.
|
||||||
//
|
//
|
||||||
// Parameters are as in walkrange: "for v1, v2 = range a".
|
// Parameters are as in walkrange: "for v1, v2 = range a".
|
||||||
func arrayClear(n, v1, v2, a ir.Node) bool {
|
func arrayClear(loop, v1, v2, a ir.Node) ir.Node {
|
||||||
if base.Flag.N != 0 || instrumenting {
|
if base.Flag.N != 0 || instrumenting {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if v1 == nil || v2 != nil {
|
if v1 == nil || v2 != nil {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Body().Len() != 1 || n.Body().First() == nil {
|
if loop.Body().Len() != 1 || loop.Body().First() == nil {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt := n.Body().First() // only stmt in body
|
stmt := loop.Body().First() // only stmt in body
|
||||||
if stmt.Op() != ir.OAS || stmt.Left().Op() != ir.OINDEX {
|
if stmt.Op() != ir.OAS || stmt.Left().Op() != ir.OINDEX {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !samesafeexpr(stmt.Left().Left(), a) || !samesafeexpr(stmt.Left().Right(), v1) {
|
if !samesafeexpr(stmt.Left().Left(), a) || !samesafeexpr(stmt.Left().Right(), v1) {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
elemsize := n.Type().Elem().Width
|
elemsize := loop.Type().Elem().Width
|
||||||
if elemsize <= 0 || !isZero(stmt.Right()) {
|
if elemsize <= 0 || !isZero(stmt.Right()) {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to
|
// Convert to
|
||||||
|
|
@ -568,8 +563,7 @@ func arrayClear(n, v1, v2, a ir.Node) bool {
|
||||||
// memclr{NoHeap,Has}Pointers(hp, hn)
|
// memclr{NoHeap,Has}Pointers(hp, hn)
|
||||||
// i = len(a) - 1
|
// i = len(a) - 1
|
||||||
// }
|
// }
|
||||||
n.SetOp(ir.OIF)
|
n := ir.Nod(ir.OIF, nil, nil)
|
||||||
|
|
||||||
n.PtrBody().Set(nil)
|
n.PtrBody().Set(nil)
|
||||||
n.SetLeft(ir.Nod(ir.ONE, ir.Nod(ir.OLEN, a, nil), nodintconst(0)))
|
n.SetLeft(ir.Nod(ir.ONE, ir.Nod(ir.OLEN, a, nil), nodintconst(0)))
|
||||||
|
|
||||||
|
|
@ -611,7 +605,7 @@ func arrayClear(n, v1, v2, a ir.Node) bool {
|
||||||
n.SetLeft(defaultlit(n.Left(), nil))
|
n.SetLeft(defaultlit(n.Left(), nil))
|
||||||
typecheckslice(n.Body().Slice(), ctxStmt)
|
typecheckslice(n.Body().Slice(), ctxStmt)
|
||||||
n = walkstmt(n)
|
n = walkstmt(n)
|
||||||
return true
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// addptr returns (*T)(uintptr(p) + n).
|
// addptr returns (*T)(uintptr(p) + n).
|
||||||
|
|
|
||||||
|
|
@ -47,36 +47,30 @@ func typecheckselect(sel ir.Node) {
|
||||||
}
|
}
|
||||||
base.ErrorfAt(pos, "select case must be receive, send or assign recv")
|
base.ErrorfAt(pos, "select case must be receive, send or assign recv")
|
||||||
|
|
||||||
// convert x = <-c into OSELRECV(x, <-c).
|
|
||||||
// remove implicit conversions; the eventual assignment
|
|
||||||
// will reintroduce them.
|
|
||||||
case ir.OAS:
|
case ir.OAS:
|
||||||
|
// convert x = <-c into OSELRECV(x, <-c).
|
||||||
|
// remove implicit conversions; the eventual assignment
|
||||||
|
// will reintroduce them.
|
||||||
if (n.Right().Op() == ir.OCONVNOP || n.Right().Op() == ir.OCONVIFACE) && n.Right().Implicit() {
|
if (n.Right().Op() == ir.OCONVNOP || n.Right().Op() == ir.OCONVIFACE) && n.Right().Implicit() {
|
||||||
n.SetRight(n.Right().Left())
|
n.SetRight(n.Right().Left())
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Right().Op() != ir.ORECV {
|
if n.Right().Op() != ir.ORECV {
|
||||||
base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
|
base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
n.SetOp(ir.OSELRECV)
|
n.SetOp(ir.OSELRECV)
|
||||||
|
|
||||||
// convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok
|
|
||||||
case ir.OAS2RECV:
|
case ir.OAS2RECV:
|
||||||
if n.Right().Op() != ir.ORECV {
|
// convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok
|
||||||
|
if n.Rlist().First().Op() != ir.ORECV {
|
||||||
base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
|
base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
n.SetOp(ir.OSELRECV2)
|
n.SetOp(ir.OSELRECV2)
|
||||||
n.SetLeft(n.List().First())
|
|
||||||
n.PtrList().Set1(n.List().Second())
|
|
||||||
|
|
||||||
// convert <-c into OSELRECV(N, <-c)
|
|
||||||
case ir.ORECV:
|
case ir.ORECV:
|
||||||
n = ir.NodAt(n.Pos(), ir.OSELRECV, nil, n)
|
// convert <-c into OSELRECV(_, <-c)
|
||||||
|
n = ir.NodAt(n.Pos(), ir.OSELRECV, ir.BlankNode, n)
|
||||||
n.SetTypecheck(1)
|
n.SetTypecheck(1)
|
||||||
ncase.SetLeft(n)
|
ncase.SetLeft(n)
|
||||||
|
|
||||||
|
|
@ -134,28 +128,19 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||||
case ir.OSEND:
|
case ir.OSEND:
|
||||||
// already ok
|
// already ok
|
||||||
|
|
||||||
case ir.OSELRECV, ir.OSELRECV2:
|
case ir.OSELRECV:
|
||||||
if n.Op() == ir.OSELRECV || n.List().Len() == 0 {
|
if ir.IsBlank(n.Left()) {
|
||||||
if n.Left() == nil {
|
n = n.Right()
|
||||||
n = n.Right()
|
|
||||||
} else {
|
|
||||||
n.SetOp(ir.OAS)
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
n.SetOp(ir.OAS)
|
||||||
|
|
||||||
if n.Left() == nil {
|
case ir.OSELRECV2:
|
||||||
ir.BlankNode = typecheck(ir.BlankNode, ctxExpr|ctxAssign)
|
if ir.IsBlank(n.List().First()) && ir.IsBlank(n.List().Second()) {
|
||||||
n.SetLeft(ir.BlankNode)
|
n = n.Rlist().First()
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
n.SetOp(ir.OAS2RECV)
|
||||||
n.SetOp(ir.OAS2)
|
|
||||||
n.PtrList().Prepend(n.Left())
|
|
||||||
n.PtrRlist().Set1(n.Right())
|
|
||||||
n.SetRight(nil)
|
|
||||||
n.SetLeft(nil)
|
|
||||||
n.SetTypecheck(0)
|
|
||||||
n = typecheck(n, ctxStmt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
l = append(l, n)
|
l = append(l, n)
|
||||||
|
|
@ -176,20 +161,30 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||||
dflt = cas
|
dflt = cas
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lower x, _ = <-c to x = <-c.
|
||||||
|
if n.Op() == ir.OSELRECV2 && ir.IsBlank(n.List().Second()) {
|
||||||
|
n = ir.NodAt(n.Pos(), ir.OSELRECV, n.List().First(), n.Rlist().First())
|
||||||
|
n.SetTypecheck(1)
|
||||||
|
cas.SetLeft(n)
|
||||||
|
}
|
||||||
|
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
case ir.OSEND:
|
case ir.OSEND:
|
||||||
n.SetRight(ir.Nod(ir.OADDR, n.Right(), nil))
|
n.SetRight(ir.Nod(ir.OADDR, n.Right(), nil))
|
||||||
n.SetRight(typecheck(n.Right(), ctxExpr))
|
n.SetRight(typecheck(n.Right(), ctxExpr))
|
||||||
|
|
||||||
case ir.OSELRECV, ir.OSELRECV2:
|
case ir.OSELRECV:
|
||||||
if n.Op() == ir.OSELRECV2 && n.List().Len() == 0 {
|
if !ir.IsBlank(n.Left()) {
|
||||||
n.SetOp(ir.OSELRECV)
|
|
||||||
}
|
|
||||||
|
|
||||||
if n.Left() != nil {
|
|
||||||
n.SetLeft(ir.Nod(ir.OADDR, n.Left(), nil))
|
n.SetLeft(ir.Nod(ir.OADDR, n.Left(), nil))
|
||||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ir.OSELRECV2:
|
||||||
|
if !ir.IsBlank(n.List().First()) {
|
||||||
|
n.List().SetIndex(0, ir.Nod(ir.OADDR, n.List().First(), nil))
|
||||||
|
n.List().SetIndex(0, typecheck(n.List().First(), ctxExpr))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -204,6 +199,7 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||||
setlineno(n)
|
setlineno(n)
|
||||||
r := ir.Nod(ir.OIF, nil, nil)
|
r := ir.Nod(ir.OIF, nil, nil)
|
||||||
r.PtrInit().Set(cas.Init().Slice())
|
r.PtrInit().Set(cas.Init().Slice())
|
||||||
|
var call ir.Node
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
default:
|
default:
|
||||||
base.Fatalf("select %v", n.Op())
|
base.Fatalf("select %v", n.Op())
|
||||||
|
|
@ -211,30 +207,30 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||||
case ir.OSEND:
|
case ir.OSEND:
|
||||||
// if selectnbsend(c, v) { body } else { default body }
|
// if selectnbsend(c, v) { body } else { default body }
|
||||||
ch := n.Left()
|
ch := n.Left()
|
||||||
r.SetLeft(mkcall1(chanfn("selectnbsend", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), ch, n.Right()))
|
call = mkcall1(chanfn("selectnbsend", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), ch, n.Right())
|
||||||
|
|
||||||
case ir.OSELRECV:
|
case ir.OSELRECV:
|
||||||
// if selectnbrecv(&v, c) { body } else { default body }
|
// if selectnbrecv(&v, c) { body } else { default body }
|
||||||
ch := n.Right().Left()
|
ch := n.Right().Left()
|
||||||
elem := n.Left()
|
elem := n.Left()
|
||||||
if elem == nil {
|
if ir.IsBlank(elem) {
|
||||||
elem = nodnil()
|
elem = nodnil()
|
||||||
}
|
}
|
||||||
r.SetLeft(mkcall1(chanfn("selectnbrecv", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, ch))
|
call = mkcall1(chanfn("selectnbrecv", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, ch)
|
||||||
|
|
||||||
case ir.OSELRECV2:
|
case ir.OSELRECV2:
|
||||||
// if selectnbrecv2(&v, &received, c) { body } else { default body }
|
// if selectnbrecv2(&v, &received, c) { body } else { default body }
|
||||||
ch := n.Right().Left()
|
ch := n.Rlist().First().Left()
|
||||||
elem := n.Left()
|
elem := n.List().First()
|
||||||
if elem == nil {
|
if ir.IsBlank(elem) {
|
||||||
elem = nodnil()
|
elem = nodnil()
|
||||||
}
|
}
|
||||||
receivedp := ir.Nod(ir.OADDR, n.List().First(), nil)
|
receivedp := ir.Nod(ir.OADDR, n.List().Second(), nil)
|
||||||
receivedp = typecheck(receivedp, ctxExpr)
|
receivedp = typecheck(receivedp, ctxExpr)
|
||||||
r.SetLeft(mkcall1(chanfn("selectnbrecv2", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, receivedp, ch))
|
call = mkcall1(chanfn("selectnbrecv2", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, receivedp, ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.SetLeft(typecheck(r.Left(), ctxExpr))
|
r.SetLeft(typecheck(call, ctxExpr))
|
||||||
r.PtrBody().Set(cas.Body().Slice())
|
r.PtrBody().Set(cas.Body().Slice())
|
||||||
r.PtrRlist().Set(append(dflt.Init().Slice(), dflt.Body().Slice()...))
|
r.PtrRlist().Set(append(dflt.Init().Slice(), dflt.Body().Slice()...))
|
||||||
return []ir.Node{r, ir.Nod(ir.OBREAK, nil, nil)}
|
return []ir.Node{r, ir.Nod(ir.OBREAK, nil, nil)}
|
||||||
|
|
@ -288,11 +284,16 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||||
nsends++
|
nsends++
|
||||||
c = n.Left()
|
c = n.Left()
|
||||||
elem = n.Right()
|
elem = n.Right()
|
||||||
case ir.OSELRECV, ir.OSELRECV2:
|
case ir.OSELRECV:
|
||||||
nrecvs++
|
nrecvs++
|
||||||
i = ncas - nrecvs
|
i = ncas - nrecvs
|
||||||
c = n.Right().Left()
|
c = n.Right().Left()
|
||||||
elem = n.Left()
|
elem = n.Left()
|
||||||
|
case ir.OSELRECV2:
|
||||||
|
nrecvs++
|
||||||
|
i = ncas - nrecvs
|
||||||
|
c = n.Rlist().First().Left()
|
||||||
|
elem = n.List().First()
|
||||||
}
|
}
|
||||||
|
|
||||||
casorder[i] = cas
|
casorder[i] = cas
|
||||||
|
|
@ -305,7 +306,7 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||||
|
|
||||||
c = convnop(c, types.Types[types.TUNSAFEPTR])
|
c = convnop(c, types.Types[types.TUNSAFEPTR])
|
||||||
setField("c", c)
|
setField("c", c)
|
||||||
if elem != nil {
|
if !ir.IsBlank(elem) {
|
||||||
elem = convnop(elem, types.Types[types.TUNSAFEPTR])
|
elem = convnop(elem, types.Types[types.TUNSAFEPTR])
|
||||||
setField("elem", elem)
|
setField("elem", elem)
|
||||||
}
|
}
|
||||||
|
|
@ -347,7 +348,7 @@ func walkselectcases(cases *ir.Nodes) []ir.Node {
|
||||||
r := ir.Nod(ir.OIF, cond, nil)
|
r := ir.Nod(ir.OIF, cond, nil)
|
||||||
|
|
||||||
if n := cas.Left(); n != nil && n.Op() == ir.OSELRECV2 {
|
if n := cas.Left(); n != nil && n.Op() == ir.OSELRECV2 {
|
||||||
x := ir.Nod(ir.OAS, n.List().First(), recvOK)
|
x := ir.Nod(ir.OAS, n.List().Second(), recvOK)
|
||||||
x = typecheck(x, ctxStmt)
|
x = typecheck(x, ctxStmt)
|
||||||
r.PtrBody().Append(x)
|
r.PtrBody().Append(x)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1120,9 +1120,9 @@ func (s *state) stmt(n ir.Node) {
|
||||||
s.callResult(n.Left(), callGo)
|
s.callResult(n.Left(), callGo)
|
||||||
|
|
||||||
case ir.OAS2DOTTYPE:
|
case ir.OAS2DOTTYPE:
|
||||||
res, resok := s.dottype(n.Right(), true)
|
res, resok := s.dottype(n.Rlist().First(), true)
|
||||||
deref := false
|
deref := false
|
||||||
if !canSSAType(n.Right().Type()) {
|
if !canSSAType(n.Rlist().First().Type()) {
|
||||||
if res.Op != ssa.OpLoad {
|
if res.Op != ssa.OpLoad {
|
||||||
s.Fatalf("dottype of non-load")
|
s.Fatalf("dottype of non-load")
|
||||||
}
|
}
|
||||||
|
|
@ -1142,10 +1142,10 @@ func (s *state) stmt(n ir.Node) {
|
||||||
|
|
||||||
case ir.OAS2FUNC:
|
case ir.OAS2FUNC:
|
||||||
// We come here only when it is an intrinsic call returning two values.
|
// We come here only when it is an intrinsic call returning two values.
|
||||||
if !isIntrinsicCall(n.Right()) {
|
if !isIntrinsicCall(n.Rlist().First()) {
|
||||||
s.Fatalf("non-intrinsic AS2FUNC not expanded %v", n.Right())
|
s.Fatalf("non-intrinsic AS2FUNC not expanded %v", n.Rlist().First())
|
||||||
}
|
}
|
||||||
v := s.intrinsicCall(n.Right())
|
v := s.intrinsicCall(n.Rlist().First())
|
||||||
v1 := s.newValue1(ssa.OpSelect0, n.List().First().Type(), v)
|
v1 := s.newValue1(ssa.OpSelect0, n.List().First().Type(), v)
|
||||||
v2 := s.newValue1(ssa.OpSelect1, n.List().Second().Type(), v)
|
v2 := s.newValue1(ssa.OpSelect1, n.List().Second().Type(), v)
|
||||||
s.assign(n.List().First(), v1, false, 0)
|
s.assign(n.List().First(), v1, false, 0)
|
||||||
|
|
|
||||||
|
|
@ -3330,8 +3330,6 @@ func typecheckas2(n ir.Node) {
|
||||||
goto mismatch
|
goto mismatch
|
||||||
}
|
}
|
||||||
n.SetOp(ir.OAS2FUNC)
|
n.SetOp(ir.OAS2FUNC)
|
||||||
n.SetRight(r)
|
|
||||||
n.PtrRlist().Set(nil)
|
|
||||||
for i, l := range n.List().Slice() {
|
for i, l := range n.List().Slice() {
|
||||||
f := r.Type().Field(i)
|
f := r.Type().Field(i)
|
||||||
if f.Type != nil && l.Type() != nil {
|
if f.Type != nil && l.Type() != nil {
|
||||||
|
|
@ -3361,8 +3359,6 @@ func typecheckas2(n ir.Node) {
|
||||||
n.SetOp(ir.OAS2DOTTYPE)
|
n.SetOp(ir.OAS2DOTTYPE)
|
||||||
r.SetOp(ir.ODOTTYPE2)
|
r.SetOp(ir.ODOTTYPE2)
|
||||||
}
|
}
|
||||||
n.SetRight(r)
|
|
||||||
n.PtrRlist().Set(nil)
|
|
||||||
if l.Type() != nil {
|
if l.Type() != nil {
|
||||||
checkassignto(r.Type(), l)
|
checkassignto(r.Type(), l)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,7 @@ func lexinit() {
|
||||||
types.Types[types.TBLANK] = types.New(types.TBLANK)
|
types.Types[types.TBLANK] = types.New(types.TBLANK)
|
||||||
ir.AsNode(s.Def).SetType(types.Types[types.TBLANK])
|
ir.AsNode(s.Def).SetType(types.Types[types.TBLANK])
|
||||||
ir.BlankNode = ir.AsNode(s.Def)
|
ir.BlankNode = ir.AsNode(s.Def)
|
||||||
|
ir.BlankNode.SetTypecheck(1)
|
||||||
|
|
||||||
s = ir.BuiltinPkg.Lookup("_")
|
s = ir.BuiltinPkg.Lookup("_")
|
||||||
s.Block = -100
|
s.Block = -100
|
||||||
|
|
|
||||||
|
|
@ -604,11 +604,8 @@ opswitch:
|
||||||
|
|
||||||
if n.Op() == ir.OASOP {
|
if n.Op() == ir.OASOP {
|
||||||
// Rewrite x op= y into x = x op y.
|
// Rewrite x op= y into x = x op y.
|
||||||
n.SetRight(ir.Nod(n.SubOp(), n.Left(), n.Right()))
|
n = ir.Nod(ir.OAS, n.Left(),
|
||||||
n.SetRight(typecheck(n.Right(), ctxExpr))
|
typecheck(ir.Nod(n.SubOp(), n.Left(), n.Right()), ctxExpr))
|
||||||
|
|
||||||
n.SetOp(ir.OAS)
|
|
||||||
n.ResetAux()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if oaslit(n, init) {
|
if oaslit(n, init) {
|
||||||
|
|
@ -683,12 +680,12 @@ opswitch:
|
||||||
case ir.OAS2FUNC:
|
case ir.OAS2FUNC:
|
||||||
init.AppendNodes(n.PtrInit())
|
init.AppendNodes(n.PtrInit())
|
||||||
|
|
||||||
r := n.Right()
|
r := n.Rlist().First()
|
||||||
walkexprlistsafe(n.List().Slice(), init)
|
walkexprlistsafe(n.List().Slice(), init)
|
||||||
r = walkexpr(r, init)
|
r = walkexpr(r, init)
|
||||||
|
|
||||||
if isIntrinsicCall(r) {
|
if isIntrinsicCall(r) {
|
||||||
n.SetRight(r)
|
n.PtrRlist().Set1(r)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
init.Append(r)
|
init.Append(r)
|
||||||
|
|
@ -701,7 +698,7 @@ opswitch:
|
||||||
case ir.OAS2RECV:
|
case ir.OAS2RECV:
|
||||||
init.AppendNodes(n.PtrInit())
|
init.AppendNodes(n.PtrInit())
|
||||||
|
|
||||||
r := n.Right()
|
r := n.Rlist().First()
|
||||||
walkexprlistsafe(n.List().Slice(), init)
|
walkexprlistsafe(n.List().Slice(), init)
|
||||||
r.SetLeft(walkexpr(r.Left(), init))
|
r.SetLeft(walkexpr(r.Left(), init))
|
||||||
var n1 ir.Node
|
var n1 ir.Node
|
||||||
|
|
@ -720,7 +717,7 @@ opswitch:
|
||||||
case ir.OAS2MAPR:
|
case ir.OAS2MAPR:
|
||||||
init.AppendNodes(n.PtrInit())
|
init.AppendNodes(n.PtrInit())
|
||||||
|
|
||||||
r := n.Right()
|
r := n.Rlist().First()
|
||||||
walkexprlistsafe(n.List().Slice(), init)
|
walkexprlistsafe(n.List().Slice(), init)
|
||||||
r.SetLeft(walkexpr(r.Left(), init))
|
r.SetLeft(walkexpr(r.Left(), init))
|
||||||
r.SetRight(walkexpr(r.Right(), init))
|
r.SetRight(walkexpr(r.Right(), init))
|
||||||
|
|
@ -759,7 +756,7 @@ opswitch:
|
||||||
if ok := n.List().Second(); !ir.IsBlank(ok) && ok.Type().IsBoolean() {
|
if ok := n.List().Second(); !ir.IsBlank(ok) && ok.Type().IsBoolean() {
|
||||||
r.Type().Field(1).Type = ok.Type()
|
r.Type().Field(1).Type = ok.Type()
|
||||||
}
|
}
|
||||||
n.SetRight(r)
|
n.PtrRlist().Set1(r)
|
||||||
n.SetOp(ir.OAS2FUNC)
|
n.SetOp(ir.OAS2FUNC)
|
||||||
|
|
||||||
// don't generate a = *var if a is _
|
// don't generate a = *var if a is _
|
||||||
|
|
@ -793,7 +790,7 @@ opswitch:
|
||||||
|
|
||||||
case ir.OAS2DOTTYPE:
|
case ir.OAS2DOTTYPE:
|
||||||
walkexprlistsafe(n.List().Slice(), init)
|
walkexprlistsafe(n.List().Slice(), init)
|
||||||
n.SetRight(walkexpr(n.Right(), init))
|
n.PtrRlist().SetIndex(0, walkexpr(n.Rlist().First(), init))
|
||||||
|
|
||||||
case ir.OCONVIFACE:
|
case ir.OCONVIFACE:
|
||||||
n.SetLeft(walkexpr(n.Left(), init))
|
n.SetLeft(walkexpr(n.Left(), init))
|
||||||
|
|
|
||||||
|
|
@ -939,15 +939,12 @@ func stmtFmt(n Node, s fmt.State, mode FmtMode) {
|
||||||
|
|
||||||
mode.Fprintf(s, "%v %#v= %v", n.Left(), n.SubOp(), n.Right())
|
mode.Fprintf(s, "%v %#v= %v", n.Left(), n.SubOp(), n.Right())
|
||||||
|
|
||||||
case OAS2:
|
case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
|
||||||
if n.Colas() && !complexinit {
|
if n.Colas() && !complexinit {
|
||||||
mode.Fprintf(s, "%.v := %.v", n.List(), n.Rlist())
|
mode.Fprintf(s, "%.v := %.v", n.List(), n.Rlist())
|
||||||
break
|
} else {
|
||||||
|
mode.Fprintf(s, "%.v = %.v", n.List(), n.Rlist())
|
||||||
}
|
}
|
||||||
fallthrough
|
|
||||||
|
|
||||||
case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
|
|
||||||
mode.Fprintf(s, "%.v = %v", n.List(), n.Right())
|
|
||||||
|
|
||||||
case ORETURN:
|
case ORETURN:
|
||||||
mode.Fprintf(s, "return %.v", n.List())
|
mode.Fprintf(s, "return %.v", n.List())
|
||||||
|
|
|
||||||
|
|
@ -520,8 +520,8 @@ const (
|
||||||
ORECOVER // recover()
|
ORECOVER // recover()
|
||||||
ORECV // <-Left
|
ORECV // <-Left
|
||||||
ORUNESTR // Type(Left) (Type is string, Left is rune)
|
ORUNESTR // Type(Left) (Type is string, Left is rune)
|
||||||
OSELRECV // Left = <-Right.Left: (appears as .Left of OCASE; Right.Op == ORECV)
|
OSELRECV // like OAS: Left = Right where Right.Op = ORECV (appears as .Left of OCASE)
|
||||||
OSELRECV2 // List = <-Right.Left: (appears as .Left of OCASE; count(List) == 2, Right.Op == ORECV)
|
OSELRECV2 // like OAS2: List = Rlist where len(List)=2, len(Rlist)=1, Rlist[0].Op = ORECV (appears as .Left of OCASE)
|
||||||
OIOTA // iota
|
OIOTA // iota
|
||||||
OREAL // real(Left)
|
OREAL // real(Left)
|
||||||
OIMAG // imag(Left)
|
OIMAG // imag(Left)
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ func TestLogOpt(t *testing.T) {
|
||||||
// Check at both 1 and 8-byte alignments.
|
// Check at both 1 and 8-byte alignments.
|
||||||
t.Run("Copy", func(t *testing.T) {
|
t.Run("Copy", func(t *testing.T) {
|
||||||
const copyCode = `package x
|
const copyCode = `package x
|
||||||
func s128a1(x *[128]int8) [128]int8 {
|
func s128a1(x *[128]int8) [128]int8 {
|
||||||
return *x
|
return *x
|
||||||
}
|
}
|
||||||
func s127a1(x *[127]int8) [127]int8 {
|
func s127a1(x *[127]int8) [127]int8 {
|
||||||
|
|
@ -219,7 +219,7 @@ func s15a8(x *[15]int64) [15]int64 {
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from \u0026y.b (address-of)"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from \u0026y.b (address-of)"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":9},"end":{"line":4,"character":9}}},"message":"inlineLoc"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":9},"end":{"line":4,"character":9}}},"message":"inlineLoc"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from ~R0 = \u003cN\u003e (assign-pair)"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from ~R0 = \u0026y.b (assign-pair)"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: flow: ~r2 = ~R0:"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: flow: ~r2 = ~R0:"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: from return (*int)(~R0) (return)"}]}`)
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: from return (*int)(~R0) (return)"}]}`)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue