[dev.regabi] cmd/compile: remove Node.Left etc [generated]

This automated CL adds type assertions on the true branches of
n.Op() equality tests, to redeclare n with a more specific type, when
it is safe to do so. (That is, when n is not reassigned with a more
general type, when n is not reassigned and then used outside the
scope, and so on.) All the "unsafe" times that the automated tool
would avoid have been removed or rewritten in earlier CLs, so that
after this CL and the next one, which removes the use of ir.Nod,
every use of the Left, Right, and so on methods is done using concrete
types, never the Node interface.

Having done that, the CL locks in the progress by deleting many of
the access methods, including Left, SetLeft and so on, from the
Node interface.

There are still uses of Name, Func, Sym, some of the tracking
bits, and a few other miscellaneous fields, but all the main access
methods are gone from the Node interface. The others will be cleaned
up in smaller CLs.

Passes buildall w/ toolstash -cmp.

[git-generate]
cd src/cmd/compile/internal/gc
rf 'typeassert {
        import "cmd/compile/internal/ir"
        var n ir.Node

        n.Op() == ir.OADD -> n.(*ir.BinaryExpr)
        n.Op() == ir.OADDR -> n.(*ir.AddrExpr)
        n.Op() == ir.OADDSTR -> n.(*ir.AddStringExpr)
        n.Op() == ir.OALIGNOF -> n.(*ir.UnaryExpr)
        n.Op() == ir.OAND -> n.(*ir.BinaryExpr)
        n.Op() == ir.OANDAND -> n.(*ir.LogicalExpr)
        n.Op() == ir.OANDNOT -> n.(*ir.BinaryExpr)
        n.Op() == ir.OAPPEND -> n.(*ir.CallExpr)
        n.Op() == ir.OARRAYLIT -> n.(*ir.CompLitExpr)
        n.Op() == ir.OAS -> n.(*ir.AssignStmt)
        n.Op() == ir.OAS2 -> n.(*ir.AssignListStmt)
        n.Op() == ir.OAS2DOTTYPE -> n.(*ir.AssignListStmt)
        n.Op() == ir.OAS2FUNC -> n.(*ir.AssignListStmt)
        n.Op() == ir.OAS2MAPR -> n.(*ir.AssignListStmt)
        n.Op() == ir.OAS2RECV -> n.(*ir.AssignListStmt)
        n.Op() == ir.OASOP -> n.(*ir.AssignOpStmt)
        n.Op() == ir.OBITNOT -> n.(*ir.UnaryExpr)
        n.Op() == ir.OBLOCK -> n.(*ir.BlockStmt)
        n.Op() == ir.OBREAK -> n.(*ir.BranchStmt)
        n.Op() == ir.OBYTES2STR -> n.(*ir.ConvExpr)
        n.Op() == ir.OBYTES2STRTMP -> n.(*ir.ConvExpr)
        n.Op() == ir.OCALL -> n.(*ir.CallExpr)
        n.Op() == ir.OCALLFUNC -> n.(*ir.CallExpr)
        n.Op() == ir.OCALLINTER -> n.(*ir.CallExpr)
        n.Op() == ir.OCALLMETH -> n.(*ir.CallExpr)
        n.Op() == ir.OCALLPART -> n.(*ir.CallPartExpr)
        n.Op() == ir.OCAP -> n.(*ir.UnaryExpr)
        n.Op() == ir.OCASE -> n.(*ir.CaseStmt)
        n.Op() == ir.OCFUNC -> n.(*ir.UnaryExpr)
        n.Op() == ir.OCHECKNIL -> n.(*ir.UnaryExpr)
        n.Op() == ir.OCLOSE -> n.(*ir.UnaryExpr)
        n.Op() == ir.OCOMPLEX -> n.(*ir.BinaryExpr)
        n.Op() == ir.OCOMPLIT -> n.(*ir.CompLitExpr)
        n.Op() == ir.OCONTINUE -> n.(*ir.BranchStmt)
        n.Op() == ir.OCONV -> n.(*ir.ConvExpr)
        n.Op() == ir.OCONVIFACE -> n.(*ir.ConvExpr)
        n.Op() == ir.OCONVNOP -> n.(*ir.ConvExpr)
        n.Op() == ir.OCOPY -> n.(*ir.BinaryExpr)
        n.Op() == ir.ODCL -> n.(*ir.Decl)
        n.Op() == ir.ODCLCONST -> n.(*ir.Decl)
        n.Op() == ir.ODCLFUNC -> n.(*ir.Func)
        n.Op() == ir.ODCLTYPE -> n.(*ir.Decl)
        n.Op() == ir.ODEFER -> n.(*ir.GoDeferStmt)
        n.Op() == ir.ODELETE -> n.(*ir.CallExpr)
        n.Op() == ir.ODEREF -> n.(*ir.StarExpr)
        n.Op() == ir.ODIV -> n.(*ir.BinaryExpr)
        n.Op() == ir.ODOT -> n.(*ir.SelectorExpr)
        n.Op() == ir.ODOTINTER -> n.(*ir.SelectorExpr)
        n.Op() == ir.ODOTMETH -> n.(*ir.SelectorExpr)
        n.Op() == ir.ODOTPTR -> n.(*ir.SelectorExpr)
        n.Op() == ir.ODOTTYPE -> n.(*ir.TypeAssertExpr)
        n.Op() == ir.ODOTTYPE2 -> n.(*ir.TypeAssertExpr)
        n.Op() == ir.OEFACE -> n.(*ir.BinaryExpr)
        n.Op() == ir.OEQ -> n.(*ir.BinaryExpr)
        n.Op() == ir.OFALL -> n.(*ir.BranchStmt)
        n.Op() == ir.OFOR -> n.(*ir.ForStmt)
        n.Op() == ir.OFORUNTIL -> n.(*ir.ForStmt)
        n.Op() == ir.OGE -> n.(*ir.BinaryExpr)
        n.Op() == ir.OGETG -> n.(*ir.CallExpr)
        n.Op() == ir.OGO -> n.(*ir.GoDeferStmt)
        n.Op() == ir.OGOTO -> n.(*ir.BranchStmt)
        n.Op() == ir.OGT -> n.(*ir.BinaryExpr)
        n.Op() == ir.OIDATA -> n.(*ir.UnaryExpr)
        n.Op() == ir.OIF -> n.(*ir.IfStmt)
        n.Op() == ir.OIMAG -> n.(*ir.UnaryExpr)
        n.Op() == ir.OINDEX -> n.(*ir.IndexExpr)
        n.Op() == ir.OINDEXMAP -> n.(*ir.IndexExpr)
        n.Op() == ir.OINLCALL -> n.(*ir.InlinedCallExpr)
        n.Op() == ir.OINLMARK -> n.(*ir.InlineMarkStmt)
        n.Op() == ir.OITAB -> n.(*ir.UnaryExpr)
        n.Op() == ir.OKEY -> n.(*ir.KeyExpr)
        n.Op() == ir.OLABEL -> n.(*ir.LabelStmt)
        n.Op() == ir.OLE -> n.(*ir.BinaryExpr)
        n.Op() == ir.OLEN -> n.(*ir.UnaryExpr)
        n.Op() == ir.OLSH -> n.(*ir.BinaryExpr)
        n.Op() == ir.OLT -> n.(*ir.BinaryExpr)
        n.Op() == ir.OMAKE -> n.(*ir.CallExpr)
        n.Op() == ir.OMAKECHAN -> n.(*ir.MakeExpr)
        n.Op() == ir.OMAKEMAP -> n.(*ir.MakeExpr)
        n.Op() == ir.OMAKESLICE -> n.(*ir.MakeExpr)
        n.Op() == ir.OMAKESLICECOPY -> n.(*ir.MakeExpr)
        n.Op() == ir.OMAPLIT -> n.(*ir.CompLitExpr)
        n.Op() == ir.OMETHEXPR -> n.(*ir.MethodExpr)
        n.Op() == ir.OMOD -> n.(*ir.BinaryExpr)
        n.Op() == ir.OMUL -> n.(*ir.BinaryExpr)
        n.Op() == ir.ONAME -> n.(*ir.Name)
        n.Op() == ir.ONE -> n.(*ir.BinaryExpr)
        n.Op() == ir.ONEG -> n.(*ir.UnaryExpr)
        n.Op() == ir.ONEW -> n.(*ir.UnaryExpr)
        n.Op() == ir.ONEWOBJ -> n.(*ir.UnaryExpr)
        n.Op() == ir.ONIL -> n.(*ir.NilExpr)
        n.Op() == ir.ONOT -> n.(*ir.UnaryExpr)
        n.Op() == ir.OOFFSETOF -> n.(*ir.UnaryExpr)
        n.Op() == ir.OOR -> n.(*ir.BinaryExpr)
        n.Op() == ir.OOROR -> n.(*ir.LogicalExpr)
        n.Op() == ir.OPACK -> n.(*ir.PkgName)
        n.Op() == ir.OPANIC -> n.(*ir.UnaryExpr)
        n.Op() == ir.OPAREN -> n.(*ir.ParenExpr)
        n.Op() == ir.OPLUS -> n.(*ir.UnaryExpr)
        n.Op() == ir.OPRINT -> n.(*ir.CallExpr)
        n.Op() == ir.OPRINTN -> n.(*ir.CallExpr)
        n.Op() == ir.OPTRLIT -> n.(*ir.AddrExpr)
        n.Op() == ir.ORANGE -> n.(*ir.RangeStmt)
        n.Op() == ir.OREAL -> n.(*ir.UnaryExpr)
        n.Op() == ir.ORECOVER -> n.(*ir.CallExpr)
        n.Op() == ir.ORECV -> n.(*ir.UnaryExpr)
        n.Op() == ir.ORESULT -> n.(*ir.ResultExpr)
        n.Op() == ir.ORETJMP -> n.(*ir.BranchStmt)
        n.Op() == ir.ORETURN -> n.(*ir.ReturnStmt)
        n.Op() == ir.ORSH -> n.(*ir.BinaryExpr)
        n.Op() == ir.ORUNES2STR -> n.(*ir.ConvExpr)
        n.Op() == ir.ORUNESTR -> n.(*ir.ConvExpr)
        n.Op() == ir.OSELECT -> n.(*ir.SelectStmt)
        n.Op() == ir.OSELRECV2 -> n.(*ir.AssignListStmt)
        n.Op() == ir.OSEND -> n.(*ir.SendStmt)
        n.Op() == ir.OSIZEOF -> n.(*ir.UnaryExpr)
        n.Op() == ir.OSLICE -> n.(*ir.SliceExpr)
        n.Op() == ir.OSLICE3 -> n.(*ir.SliceExpr)
        n.Op() == ir.OSLICE3ARR -> n.(*ir.SliceExpr)
        n.Op() == ir.OSLICEARR -> n.(*ir.SliceExpr)
        n.Op() == ir.OSLICEHEADER -> n.(*ir.SliceHeaderExpr)
        n.Op() == ir.OSLICELIT -> n.(*ir.CompLitExpr)
        n.Op() == ir.OSLICESTR -> n.(*ir.SliceExpr)
        n.Op() == ir.OSPTR -> n.(*ir.UnaryExpr)
        n.Op() == ir.OSTR2BYTES -> n.(*ir.ConvExpr)
        n.Op() == ir.OSTR2BYTESTMP -> n.(*ir.ConvExpr)
        n.Op() == ir.OSTR2RUNES -> n.(*ir.ConvExpr)
        n.Op() == ir.OSTRUCTLIT -> n.(*ir.CompLitExpr)
        n.Op() == ir.OSUB -> n.(*ir.BinaryExpr)
        n.Op() == ir.OSWITCH -> n.(*ir.SwitchStmt)
        n.Op() == ir.OTYPESW -> n.(*ir.TypeSwitchGuard)
        n.Op() == ir.OVARDEF -> n.(*ir.UnaryExpr)
        n.Op() == ir.OVARKILL -> n.(*ir.UnaryExpr)
        n.Op() == ir.OVARLIVE -> n.(*ir.UnaryExpr)
        n.Op() == ir.OXDOT -> n.(*ir.SelectorExpr)
        n.Op() == ir.OXOR -> n.(*ir.BinaryExpr)
}
'

cd ../ir
rf '
        rm \
                Node.SetOp \
                miniNode.SetOp \
                Node.Func \
                miniNode.Func \
                Node.Left Node.SetLeft \
                miniNode.Left miniNode.SetLeft \
                Node.Right Node.SetRight \
                miniNode.Right miniNode.SetRight \
                Node.List Node.PtrList Node.SetList \
                miniNode.List miniNode.PtrList miniNode.SetList \
                Node.Rlist Node.PtrRlist Node.SetRlist \
                miniNode.Rlist miniNode.PtrRlist miniNode.SetRlist \
                Node.Body Node.PtrBody Node.SetBody \
                miniNode.Body miniNode.PtrBody miniNode.SetBody \
                Node.SubOp Node.SetSubOp \
                miniNode.SubOp miniNode.SetSubOp \
                Node.SetSym \
                miniNode.SetSym \
                Node.Offset Node.SetOffset \
                miniNode.Offset miniNode.SetOffset \
                Node.Class Node.SetClass \
                miniNode.Class miniNode.SetClass \
                Node.Iota Node.SetIota \
                miniNode.Iota miniNode.SetIota \
                Node.Colas Node.SetColas \
                miniNode.Colas miniNode.SetColas \
                Node.Transient Node.SetTransient \
                miniNode.Transient miniNode.SetTransient \
                Node.Implicit Node.SetImplicit \
                miniNode.Implicit miniNode.SetImplicit \
                Node.IsDDD Node.SetIsDDD \
                miniNode.IsDDD miniNode.SetIsDDD \
                Node.MarkReadonly \
                miniNode.MarkReadonly \
                Node.Likely Node.SetLikely \
                miniNode.Likely miniNode.SetLikely \
                Node.SliceBounds Node.SetSliceBounds \
                miniNode.SliceBounds miniNode.SetSliceBounds \
                Node.NoInline Node.SetNoInline \
                miniNode.NoInline miniNode.SetNoInline \
                Node.IndexMapLValue Node.SetIndexMapLValue \
                miniNode.IndexMapLValue miniNode.SetIndexMapLValue \
                Node.ResetAux \
                miniNode.ResetAux \
                Node.HasBreak Node.SetHasBreak \
                miniNode.HasBreak miniNode.SetHasBreak \
                Node.Bounded Node.SetBounded \
                miniNode.Bounded miniNode.SetBounded \
                miniNode.Embedded miniNode.SetEmbedded \
                miniNode.Int64Val miniNode.Uint64Val miniNode.CanInt64 \
                miniNode.BoolVal miniNode.StringVal \
                miniNode.TChanDir miniNode.SetTChanDir \
                miniNode.Format \
                miniNode.copy miniNode.doChildren miniNode.editChildren \

'

Change-Id: I2a05b535963b43f83b1849fcf653f82b99af6035
Reviewed-on: https://go-review.googlesource.com/c/go/+/277934
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Russ Cox 2020-12-22 23:56:32 -05:00
parent 6f27d29be0
commit 14d667341f
19 changed files with 435 additions and 144 deletions

View file

@ -204,6 +204,7 @@ func convlit1(n ir.Node, t *types.Type, explicit bool, context func() string) ir
return n return n
case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE: case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
n := n.(*ir.BinaryExpr)
if !t.IsBoolean() { if !t.IsBoolean() {
break break
} }
@ -211,6 +212,7 @@ func convlit1(n ir.Node, t *types.Type, explicit bool, context func() string) ir
return n return n
case ir.OLSH, ir.ORSH: case ir.OLSH, ir.ORSH:
n := n.(*ir.BinaryExpr)
n.SetLeft(convlit1(n.Left(), t, explicit, nil)) n.SetLeft(convlit1(n.Left(), t, explicit, nil))
n.SetType(n.Left().Type()) n.SetType(n.Left().Type())
if n.Type() != nil && !n.Type().IsInteger() { if n.Type() != nil && !n.Type().IsInteger() {
@ -449,6 +451,7 @@ func evalConst(n ir.Node) ir.Node {
// Pick off just the opcodes that can be constant evaluated. // Pick off just the opcodes that can be constant evaluated.
switch n.Op() { switch n.Op() {
case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT: case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT:
n := n.(*ir.UnaryExpr)
nl := n.Left() nl := n.Left()
if nl.Op() == ir.OLITERAL { if nl.Op() == ir.OLITERAL {
var prec uint var prec uint
@ -459,6 +462,7 @@ func evalConst(n ir.Node) ir.Node {
} }
case ir.OADD, ir.OSUB, ir.OMUL, ir.ODIV, ir.OMOD, ir.OOR, ir.OXOR, ir.OAND, ir.OANDNOT: case ir.OADD, ir.OSUB, ir.OMUL, ir.ODIV, ir.OMOD, ir.OOR, ir.OXOR, ir.OAND, ir.OANDNOT:
n := n.(*ir.BinaryExpr)
nl, nr := n.Left(), n.Right() nl, nr := n.Left(), n.Right()
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL { if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
rval := nr.Val() rval := nr.Val()
@ -483,18 +487,21 @@ func evalConst(n ir.Node) ir.Node {
} }
case ir.OOROR, ir.OANDAND: case ir.OOROR, ir.OANDAND:
n := n.(*ir.LogicalExpr)
nl, nr := n.Left(), n.Right() nl, nr := n.Left(), n.Right()
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL { if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
return origConst(n, constant.BinaryOp(nl.Val(), tokenForOp[n.Op()], nr.Val())) return origConst(n, constant.BinaryOp(nl.Val(), tokenForOp[n.Op()], nr.Val()))
} }
case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE: case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
n := n.(*ir.BinaryExpr)
nl, nr := n.Left(), n.Right() nl, nr := n.Left(), n.Right()
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL { if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
return origBoolConst(n, constant.Compare(nl.Val(), tokenForOp[n.Op()], nr.Val())) return origBoolConst(n, constant.Compare(nl.Val(), tokenForOp[n.Op()], nr.Val()))
} }
case ir.OLSH, ir.ORSH: case ir.OLSH, ir.ORSH:
n := n.(*ir.BinaryExpr)
nl, nr := n.Left(), n.Right() nl, nr := n.Left(), n.Right()
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL { if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
// shiftBound from go/types; "so we can express smallestFloat64" // shiftBound from go/types; "so we can express smallestFloat64"
@ -509,12 +516,14 @@ func evalConst(n ir.Node) ir.Node {
} }
case ir.OCONV, ir.ORUNESTR: case ir.OCONV, ir.ORUNESTR:
n := n.(*ir.ConvExpr)
nl := n.Left() nl := n.Left()
if ir.OKForConst[n.Type().Kind()] && nl.Op() == ir.OLITERAL { if ir.OKForConst[n.Type().Kind()] && nl.Op() == ir.OLITERAL {
return origConst(n, convertVal(nl.Val(), n.Type(), true)) return origConst(n, convertVal(nl.Val(), n.Type(), true))
} }
case ir.OCONVNOP: case ir.OCONVNOP:
n := n.(*ir.ConvExpr)
nl := n.Left() nl := n.Left()
if ir.OKForConst[n.Type().Kind()] && nl.Op() == ir.OLITERAL { if ir.OKForConst[n.Type().Kind()] && nl.Op() == ir.OLITERAL {
// set so n.Orig gets OCONV instead of OCONVNOP // set so n.Orig gets OCONV instead of OCONVNOP
@ -524,6 +533,7 @@ func evalConst(n ir.Node) ir.Node {
case ir.OADDSTR: case ir.OADDSTR:
// Merge adjacent constants in the argument list. // Merge adjacent constants in the argument list.
n := n.(*ir.AddStringExpr)
s := n.List().Slice() s := n.List().Slice()
need := 0 need := 0
for i := 0; i < len(s); i++ { for i := 0; i < len(s); i++ {
@ -567,6 +577,7 @@ func evalConst(n ir.Node) ir.Node {
return nn return nn
case ir.OCAP, ir.OLEN: case ir.OCAP, ir.OLEN:
n := n.(*ir.UnaryExpr)
nl := n.Left() nl := n.Left()
switch nl.Type().Kind() { switch nl.Type().Kind() {
case types.TSTRING: case types.TSTRING:
@ -580,21 +591,25 @@ func evalConst(n ir.Node) ir.Node {
} }
case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF: case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
n := n.(*ir.UnaryExpr)
return origIntConst(n, evalunsafe(n)) return origIntConst(n, evalunsafe(n))
case ir.OREAL: case ir.OREAL:
n := n.(*ir.UnaryExpr)
nl := n.Left() nl := n.Left()
if nl.Op() == ir.OLITERAL { if nl.Op() == ir.OLITERAL {
return origConst(n, constant.Real(nl.Val())) return origConst(n, constant.Real(nl.Val()))
} }
case ir.OIMAG: case ir.OIMAG:
n := n.(*ir.UnaryExpr)
nl := n.Left() nl := n.Left()
if nl.Op() == ir.OLITERAL { if nl.Op() == ir.OLITERAL {
return origConst(n, constant.Imag(nl.Val())) return origConst(n, constant.Imag(nl.Val()))
} }
case ir.OCOMPLEX: case ir.OCOMPLEX:
n := n.(*ir.BinaryExpr)
nl, nr := n.Left(), n.Right() nl, nr := n.Left(), n.Right()
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL { if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
return origConst(n, makeComplex(nl.Val(), nr.Val())) return origConst(n, makeComplex(nl.Val(), nr.Val()))
@ -854,6 +869,7 @@ type constSetKey struct {
// n must not be an untyped constant. // n must not be an untyped constant.
func (s *constSet) add(pos src.XPos, n ir.Node, what, where string) { func (s *constSet) add(pos src.XPos, n ir.Node, what, where string) {
if conv := n; conv.Op() == ir.OCONVIFACE { if conv := n; conv.Op() == ir.OCONVIFACE {
conv := conv.(*ir.ConvExpr)
if conv.Implicit() { if conv.Implicit() {
n = conv.Left() n = conv.Left()
} }

View file

@ -229,6 +229,7 @@ func oldname(s *types.Sym) ir.Node {
// are parsing x := 5 inside the closure, until we get to // are parsing x := 5 inside the closure, until we get to
// the := it looks like a reference to the outer x so we'll // the := it looks like a reference to the outer x so we'll
// make x a closure variable unnecessarily. // make x a closure variable unnecessarily.
n := n.(*ir.Name)
c := n.Name().Innermost c := n.Name().Innermost
if c == nil || c.Curfn != Curfn { if c == nil || c.Curfn != Curfn {
// Do not have a closure var for the active closure yet; make one. // Do not have a closure var for the active closure yet; make one.
@ -890,6 +891,7 @@ func (c *nowritebarrierrecChecker) findExtraCalls(nn ir.Node) {
arg := n.List().First() arg := n.List().First()
switch arg.Op() { switch arg.Op() {
case ir.ONAME: case ir.ONAME:
arg := arg.(*ir.Name)
callee = arg.Name().Defn.(*ir.Func) callee = arg.Name().Defn.(*ir.Func)
case ir.OCLOSURE: case ir.OCLOSURE:
arg := arg.(*ir.ClosureExpr) arg := arg.(*ir.ClosureExpr)

View file

@ -1067,11 +1067,13 @@ func (w *exportWriter) stmt(n ir.Node) {
// (At the moment neither the parser nor the typechecker // (At the moment neither the parser nor the typechecker
// generate OBLOCK nodes except to denote an empty // generate OBLOCK nodes except to denote an empty
// function body, although that may change.) // function body, although that may change.)
n := n.(*ir.BlockStmt)
for _, n := range n.List().Slice() { for _, n := range n.List().Slice() {
w.stmt(n) w.stmt(n)
} }
case ir.ODCL: case ir.ODCL:
n := n.(*ir.Decl)
w.op(ir.ODCL) w.op(ir.ODCL)
w.pos(n.Left().Pos()) w.pos(n.Left().Pos())
w.localName(n.Left().(*ir.Name)) w.localName(n.Left().(*ir.Name))
@ -1081,6 +1083,7 @@ func (w *exportWriter) stmt(n ir.Node) {
// Don't export "v = <N>" initializing statements, hope they're always // Don't export "v = <N>" initializing statements, hope they're always
// preceded by the DCL which will be re-parsed and typecheck to reproduce // preceded by the DCL which will be re-parsed and typecheck to reproduce
// the "v = <N>" again. // the "v = <N>" again.
n := n.(*ir.AssignStmt)
if n.Right() != nil { if n.Right() != nil {
w.op(ir.OAS) w.op(ir.OAS)
w.pos(n.Pos()) w.pos(n.Pos())
@ -1099,12 +1102,14 @@ func (w *exportWriter) stmt(n ir.Node) {
} }
case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV: case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
n := n.(*ir.AssignListStmt)
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.ORETURN: case ir.ORETURN:
n := n.(*ir.ReturnStmt)
w.op(ir.ORETURN) w.op(ir.ORETURN)
w.pos(n.Pos()) w.pos(n.Pos())
w.exprList(n.List()) w.exprList(n.List())
@ -1113,11 +1118,13 @@ func (w *exportWriter) stmt(n ir.Node) {
// unreachable - generated by compiler for trampolin routines // unreachable - generated by compiler for trampolin routines
case ir.OGO, ir.ODEFER: case ir.OGO, ir.ODEFER:
n := n.(*ir.GoDeferStmt)
w.op(n.Op()) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
case ir.OIF: case ir.OIF:
n := n.(*ir.IfStmt)
w.op(ir.OIF) w.op(ir.OIF)
w.pos(n.Pos()) w.pos(n.Pos())
w.stmtList(n.Init()) w.stmtList(n.Init())
@ -1126,6 +1133,7 @@ func (w *exportWriter) stmt(n ir.Node) {
w.stmtList(n.Rlist()) w.stmtList(n.Rlist())
case ir.OFOR: case ir.OFOR:
n := n.(*ir.ForStmt)
w.op(ir.OFOR) w.op(ir.OFOR)
w.pos(n.Pos()) w.pos(n.Pos())
w.stmtList(n.Init()) w.stmtList(n.Init())
@ -1133,6 +1141,7 @@ func (w *exportWriter) stmt(n ir.Node) {
w.stmtList(n.Body()) w.stmtList(n.Body())
case ir.ORANGE: case ir.ORANGE:
n := n.(*ir.RangeStmt)
w.op(ir.ORANGE) w.op(ir.ORANGE)
w.pos(n.Pos()) w.pos(n.Pos())
w.stmtList(n.List()) w.stmtList(n.List())
@ -1140,6 +1149,7 @@ func (w *exportWriter) stmt(n ir.Node) {
w.stmtList(n.Body()) w.stmtList(n.Body())
case ir.OSELECT: case ir.OSELECT:
n := n.(*ir.SelectStmt)
w.op(n.Op()) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
w.stmtList(n.Init()) w.stmtList(n.Init())
@ -1147,6 +1157,7 @@ func (w *exportWriter) stmt(n ir.Node) {
w.caseList(n) w.caseList(n)
case ir.OSWITCH: case ir.OSWITCH:
n := n.(*ir.SwitchStmt)
w.op(n.Op()) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
w.stmtList(n.Init()) w.stmtList(n.Init())
@ -1157,6 +1168,7 @@ func (w *exportWriter) stmt(n ir.Node) {
// handled by caseList // handled by caseList
case ir.OFALL: case ir.OFALL:
n := n.(*ir.BranchStmt)
w.op(ir.OFALL) w.op(ir.OFALL)
w.pos(n.Pos()) w.pos(n.Pos())
@ -1217,16 +1229,20 @@ func (w *exportWriter) exprList(list ir.Nodes) {
func simplifyForExport(n ir.Node) ir.Node { func simplifyForExport(n ir.Node) ir.Node {
switch n.Op() { switch n.Op() {
case ir.OPAREN: case ir.OPAREN:
n := n.(*ir.ParenExpr)
return simplifyForExport(n.Left()) return simplifyForExport(n.Left())
case ir.ODEREF: case ir.ODEREF:
n := n.(*ir.StarExpr)
if n.Implicit() { if n.Implicit() {
return simplifyForExport(n.Left()) return simplifyForExport(n.Left())
} }
case ir.OADDR: case ir.OADDR:
n := n.(*ir.AddrExpr)
if n.Implicit() { if n.Implicit() {
return simplifyForExport(n.Left()) return simplifyForExport(n.Left())
} }
case ir.ODOT, ir.ODOTPTR: case ir.ODOT, ir.ODOTPTR:
n := n.(*ir.SelectorExpr)
if n.Implicit() { if n.Implicit() {
return simplifyForExport(n.Left()) return simplifyForExport(n.Left())
} }
@ -1240,6 +1256,7 @@ func (w *exportWriter) expr(n ir.Node) {
// expressions // expressions
// (somewhat closely following the structure of exprfmt in fmt.go) // (somewhat closely following the structure of exprfmt in fmt.go)
case ir.ONIL: case ir.ONIL:
n := n.(*ir.NilExpr)
if !n.Type().HasNil() { if !n.Type().HasNil() {
base.Fatalf("unexpected type for nil: %v", n.Type()) base.Fatalf("unexpected type for nil: %v", n.Type())
} }
@ -1284,6 +1301,7 @@ func (w *exportWriter) expr(n ir.Node) {
w.typ(n.Type()) w.typ(n.Type())
case ir.OTYPESW: case ir.OTYPESW:
n := n.(*ir.TypeSwitchGuard)
w.op(ir.OTYPESW) w.op(ir.OTYPESW)
w.pos(n.Pos()) w.pos(n.Pos())
var s *types.Sym var s *types.Sym
@ -1306,23 +1324,27 @@ func (w *exportWriter) expr(n ir.Node) {
// should have been resolved by typechecking - handled by default case // should have been resolved by typechecking - handled by default case
case ir.OPTRLIT: case ir.OPTRLIT:
n := n.(*ir.AddrExpr)
w.op(ir.OADDR) w.op(ir.OADDR)
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
case ir.OSTRUCTLIT: case ir.OSTRUCTLIT:
n := n.(*ir.CompLitExpr)
w.op(ir.OSTRUCTLIT) w.op(ir.OSTRUCTLIT)
w.pos(n.Pos()) w.pos(n.Pos())
w.typ(n.Type()) w.typ(n.Type())
w.fieldList(n.List()) // special handling of field names w.fieldList(n.List()) // special handling of field names
case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT: case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
n := n.(*ir.CompLitExpr)
w.op(ir.OCOMPLIT) w.op(ir.OCOMPLIT)
w.pos(n.Pos()) w.pos(n.Pos())
w.typ(n.Type()) w.typ(n.Type())
w.exprList(n.List()) w.exprList(n.List())
case ir.OKEY: case ir.OKEY:
n := n.(*ir.KeyExpr)
w.op(ir.OKEY) w.op(ir.OKEY)
w.pos(n.Pos()) w.pos(n.Pos())
w.exprsOrNil(n.Left(), n.Right()) w.exprsOrNil(n.Left(), n.Right())
@ -1332,30 +1354,35 @@ func (w *exportWriter) expr(n ir.Node) {
case ir.OCALLPART: case ir.OCALLPART:
// An OCALLPART is an OXDOT before type checking. // An OCALLPART is an OXDOT before type checking.
n := n.(*ir.CallPartExpr)
w.op(ir.OXDOT) w.op(ir.OXDOT)
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
w.selector(n.Sym()) w.selector(n.Sym())
case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH: case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH:
n := n.(*ir.SelectorExpr)
w.op(ir.OXDOT) w.op(ir.OXDOT)
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
w.selector(n.Sym()) w.selector(n.Sym())
case ir.ODOTTYPE, ir.ODOTTYPE2: case ir.ODOTTYPE, ir.ODOTTYPE2:
n := n.(*ir.TypeAssertExpr)
w.op(ir.ODOTTYPE) w.op(ir.ODOTTYPE)
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
w.typ(n.Type()) w.typ(n.Type())
case ir.OINDEX, ir.OINDEXMAP: case ir.OINDEX, ir.OINDEXMAP:
n := n.(*ir.IndexExpr)
w.op(ir.OINDEX) w.op(ir.OINDEX)
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
w.expr(n.Right()) w.expr(n.Right())
case ir.OSLICE, ir.OSLICESTR, ir.OSLICEARR: case ir.OSLICE, ir.OSLICESTR, ir.OSLICEARR:
n := n.(*ir.SliceExpr)
w.op(ir.OSLICE) w.op(ir.OSLICE)
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
@ -1363,6 +1390,7 @@ func (w *exportWriter) expr(n ir.Node) {
w.exprsOrNil(low, high) w.exprsOrNil(low, high)
case ir.OSLICE3, ir.OSLICE3ARR: case ir.OSLICE3, ir.OSLICE3ARR:
n := n.(*ir.SliceExpr)
w.op(ir.OSLICE3) w.op(ir.OSLICE3)
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
@ -1372,6 +1400,7 @@ func (w *exportWriter) expr(n ir.Node) {
case ir.OCOPY, ir.OCOMPLEX: case ir.OCOPY, ir.OCOMPLEX:
// treated like other builtin calls (see e.g., OREAL) // treated like other builtin calls (see e.g., OREAL)
n := n.(*ir.BinaryExpr)
w.op(n.Op()) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
@ -1379,18 +1408,21 @@ func (w *exportWriter) expr(n ir.Node) {
w.op(ir.OEND) w.op(ir.OEND)
case ir.OCONV, ir.OCONVIFACE, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR: case ir.OCONV, ir.OCONVIFACE, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR:
n := n.(*ir.ConvExpr)
w.op(ir.OCONV) w.op(ir.OCONV)
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
w.typ(n.Type()) w.typ(n.Type())
case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC: case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC:
n := n.(*ir.UnaryExpr)
w.op(n.Op()) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
w.op(ir.OEND) w.op(ir.OEND)
case ir.OAPPEND, ir.ODELETE, ir.ORECOVER, ir.OPRINT, ir.OPRINTN: case ir.OAPPEND, ir.ODELETE, ir.ORECOVER, ir.OPRINT, ir.OPRINTN:
n := n.(*ir.CallExpr)
w.op(n.Op()) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
w.exprList(n.List()) // emits terminating OEND w.exprList(n.List()) // emits terminating OEND
@ -1402,6 +1434,7 @@ func (w *exportWriter) expr(n ir.Node) {
} }
case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OGETG: case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OGETG:
n := n.(*ir.CallExpr)
w.op(ir.OCALL) w.op(ir.OCALL)
w.pos(n.Pos()) w.pos(n.Pos())
w.stmtList(n.Init()) w.stmtList(n.Init())
@ -1410,6 +1443,7 @@ func (w *exportWriter) expr(n ir.Node) {
w.bool(n.IsDDD()) w.bool(n.IsDDD())
case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE: case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE:
n := n.(*ir.MakeExpr)
w.op(n.Op()) // must keep separate from OMAKE for importer w.op(n.Op()) // must keep separate from OMAKE for importer
w.pos(n.Pos()) w.pos(n.Pos())
w.typ(n.Type()) w.typ(n.Type())
@ -1428,21 +1462,25 @@ func (w *exportWriter) expr(n ir.Node) {
// unary expressions // unary expressions
case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV: case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV:
n := n.(*ir.UnaryExpr)
w.op(n.Op()) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
case ir.OADDR: case ir.OADDR:
n := n.(*ir.AddrExpr)
w.op(n.Op()) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
case ir.ODEREF: case ir.ODEREF:
n := n.(*ir.StarExpr)
w.op(n.Op()) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
case ir.OSEND: case ir.OSEND:
n := n.(*ir.SendStmt)
w.op(n.Op()) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
@ -1451,18 +1489,21 @@ func (w *exportWriter) expr(n ir.Node) {
// binary expressions // binary expressions
case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT, case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT,
ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR: ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR:
n := n.(*ir.BinaryExpr)
w.op(n.Op()) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
w.expr(n.Right()) w.expr(n.Right())
case ir.OANDAND, ir.OOROR: case ir.OANDAND, ir.OOROR:
n := n.(*ir.LogicalExpr)
w.op(n.Op()) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.Left()) w.expr(n.Left())
w.expr(n.Right()) w.expr(n.Right())
case ir.OADDSTR: case ir.OADDSTR:
n := n.(*ir.AddStringExpr)
w.op(ir.OADDSTR) w.op(ir.OADDSTR)
w.pos(n.Pos()) w.pos(n.Pos())
w.exprList(n.List()) w.exprList(n.List())

View file

@ -756,6 +756,7 @@ func (r *importReader) stmtList() []ir.Node {
// but the handling of ODCL calls liststmt, which creates one. // but the handling of ODCL calls liststmt, which creates one.
// Inline them into the statement list. // Inline them into the statement list.
if n.Op() == ir.OBLOCK { if n.Op() == ir.OBLOCK {
n := n.(*ir.BlockStmt)
list = append(list, n.List().Slice()...) list = append(list, n.List().Slice()...)
} else { } else {
list = append(list, n) list = append(list, n)
@ -802,6 +803,7 @@ func (r *importReader) exprList() []ir.Node {
func (r *importReader) expr() ir.Node { func (r *importReader) expr() ir.Node {
n := r.node() n := r.node()
if n != nil && n.Op() == ir.OBLOCK { if n != nil && n.Op() == ir.OBLOCK {
n := n.(*ir.BlockStmt)
base.Fatalf("unexpected block node: %v", n) base.Fatalf("unexpected block node: %v", n)
} }
return n return n

View file

@ -254,10 +254,13 @@ func collectDeps(n ir.Node, transitive bool) ir.NameSet {
d := initDeps{transitive: transitive} d := initDeps{transitive: transitive}
switch n.Op() { switch n.Op() {
case ir.OAS: case ir.OAS:
n := n.(*ir.AssignStmt)
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:
n := n.(*ir.AssignListStmt)
d.inspect(n.Rlist().First()) d.inspect(n.Rlist().First())
case ir.ODCLFUNC: case ir.ODCLFUNC:
n := n.(*ir.Func)
d.inspectList(n.Body()) d.inspectList(n.Body())
default: default:
base.Fatalf("unexpected Op: %v", n.Op()) base.Fatalf("unexpected Op: %v", n.Op())
@ -286,6 +289,7 @@ func (d *initDeps) inspectList(l ir.Nodes) { ir.VisitList(l, d.cachedVisit()) }
func (d *initDeps) visit(n ir.Node) { func (d *initDeps) visit(n ir.Node) {
switch n.Op() { switch n.Op() {
case ir.OMETHEXPR: case ir.OMETHEXPR:
n := n.(*ir.MethodExpr)
d.foundDep(methodExprName(n)) d.foundDep(methodExprName(n))
case ir.ONAME: case ir.ONAME:
@ -355,8 +359,10 @@ func (s *declOrder) Pop() interface{} {
func firstLHS(n ir.Node) *ir.Name { func firstLHS(n ir.Node) *ir.Name {
switch n.Op() { switch n.Op() {
case ir.OAS: case ir.OAS:
n := n.(*ir.AssignStmt)
return n.Left().Name() return n.Left().Name()
case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2RECV, ir.OAS2MAPR: case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2RECV, ir.OAS2MAPR:
n := n.(*ir.AssignListStmt)
return n.List().First().Name() return n.List().First().Name()
} }

View file

@ -377,6 +377,7 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
// Call is okay if inlinable and we have the budget for the body. // Call is okay if inlinable and we have the budget for the body.
case ir.OCALLMETH: case ir.OCALLMETH:
n := n.(*ir.CallExpr)
t := n.Left().Type() t := n.Left().Type()
if t == nil { if t == nil {
base.Fatalf("no function type for [%p] %+v\n", n.Left(), n.Left()) base.Fatalf("no function type for [%p] %+v\n", n.Left(), n.Left())
@ -429,22 +430,26 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
return nil return nil
case ir.OFOR, ir.OFORUNTIL: case ir.OFOR, ir.OFORUNTIL:
n := n.(*ir.ForStmt)
if n.Sym() != nil { if n.Sym() != nil {
return errors.New("labeled control") return errors.New("labeled control")
} }
case ir.OSWITCH: case ir.OSWITCH:
n := n.(*ir.SwitchStmt)
if n.Sym() != nil { if n.Sym() != nil {
return errors.New("labeled control") return errors.New("labeled control")
} }
// case ir.ORANGE, ir.OSELECT in "unhandled" above // case ir.ORANGE, ir.OSELECT in "unhandled" above
case ir.OBREAK, ir.OCONTINUE: case ir.OBREAK, ir.OCONTINUE:
n := n.(*ir.BranchStmt)
if n.Sym() != nil { if n.Sym() != nil {
// Should have short-circuited due to labeled control error above. // Should have short-circuited due to labeled control error above.
base.Fatalf("unexpected labeled break/continue: %v", n) base.Fatalf("unexpected labeled break/continue: %v", n)
} }
case ir.OIF: case ir.OIF:
n := n.(*ir.IfStmt)
if ir.IsConst(n.Left(), constant.Bool) { if ir.IsConst(n.Left(), constant.Bool) {
// This if and the condition cost nothing. // This if and the condition cost nothing.
// TODO(rsc): It seems strange that we visit the dead branch. // TODO(rsc): It seems strange that we visit the dead branch.
@ -569,8 +574,10 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No
switch n.Op() { switch n.Op() {
case ir.ODEFER, ir.OGO: case ir.ODEFER, ir.OGO:
n := n.(*ir.GoDeferStmt)
switch call := n.Left(); call.Op() { switch call := n.Left(); call.Op() {
case ir.OCALLFUNC, ir.OCALLMETH: case ir.OCALLFUNC, ir.OCALLMETH:
call := call.(*ir.CallExpr)
call.SetNoInline(true) call.SetNoInline(true)
} }
@ -581,6 +588,7 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No
case ir.OCALLMETH: case ir.OCALLMETH:
// Prevent inlining some reflect.Value methods when using checkptr, // Prevent inlining some reflect.Value methods when using checkptr,
// even when package reflect was compiled without it (#35073). // even when package reflect was compiled without it (#35073).
n := n.(*ir.CallExpr)
if s := n.Left().Sym(); base.Debug.Checkptr != 0 && isReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") { if s := n.Left().Sym(); base.Debug.Checkptr != 0 && isReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
return n return n
} }
@ -591,6 +599,7 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No
ir.EditChildren(n, edit) ir.EditChildren(n, edit)
if as := n; as.Op() == ir.OAS2FUNC { if as := n; as.Op() == ir.OAS2FUNC {
as := as.(*ir.AssignListStmt)
if as.Rlist().First().Op() == ir.OINLCALL { if as.Rlist().First().Op() == ir.OINLCALL {
as.PtrRlist().Set(inlconv2list(as.Rlist().First().(*ir.InlinedCallExpr))) as.PtrRlist().Set(inlconv2list(as.Rlist().First().(*ir.InlinedCallExpr)))
as.SetOp(ir.OAS2) as.SetOp(ir.OAS2)
@ -604,6 +613,7 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No
// switch at the top of this function. // switch at the top of this function.
switch n.Op() { switch n.Op() {
case ir.OCALLFUNC, ir.OCALLMETH: case ir.OCALLFUNC, ir.OCALLMETH:
n := n.(*ir.CallExpr)
if n.NoInline() { if n.NoInline() {
return n return n
} }
@ -673,6 +683,7 @@ func inlCallee(fn ir.Node) *ir.Func {
} }
return n.Func() return n.Func()
case ir.ONAME: case ir.ONAME:
fn := fn.(*ir.Name)
if fn.Class() == ir.PFUNC { if fn.Class() == ir.PFUNC {
return fn.Func() return fn.Func()
} }
@ -721,8 +732,10 @@ func staticValue1(nn ir.Node) ir.Node {
FindRHS: FindRHS:
switch defn.Op() { switch defn.Op() {
case ir.OAS: case ir.OAS:
defn := defn.(*ir.AssignStmt)
rhs = defn.Right() rhs = defn.Right()
case ir.OAS2: case ir.OAS2:
defn := defn.(*ir.AssignListStmt)
for i, lhs := range defn.List().Slice() { for i, lhs := range defn.List().Slice() {
if lhs == n { if lhs == n {
rhs = defn.Rlist().Index(i) rhs = defn.Rlist().Index(i)
@ -761,10 +774,12 @@ func reassigned(name *ir.Name) bool {
return ir.Any(name.Curfn, func(n ir.Node) bool { return ir.Any(name.Curfn, func(n ir.Node) bool {
switch n.Op() { switch n.Op() {
case ir.OAS: case ir.OAS:
n := n.(*ir.AssignStmt)
if n.Left() == name && n != name.Defn { if n.Left() == name && n != name.Defn {
return true return true
} }
case ir.OAS2, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2DOTTYPE, ir.OAS2RECV, ir.OSELRECV2: case ir.OAS2, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2DOTTYPE, ir.OAS2RECV, ir.OSELRECV2:
n := n.(*ir.AssignListStmt)
for _, p := range n.List().Slice() { for _, p := range n.List().Slice() {
if p == name && n != name.Defn { if p == name && n != name.Defn {
return true return true
@ -1237,6 +1252,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
return n return n
case ir.OMETHEXPR: case ir.OMETHEXPR:
n := n.(*ir.MethodExpr)
return n return n
case ir.OLITERAL, ir.ONIL, ir.OTYPE: case ir.OLITERAL, ir.ONIL, ir.OTYPE:
@ -1259,6 +1275,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
case ir.ORETURN: case ir.ORETURN:
// Since we don't handle bodies with closures, // Since we don't handle bodies with closures,
// this return is guaranteed to belong to the current inlined function. // this return is guaranteed to belong to the current inlined function.
n := n.(*ir.ReturnStmt)
init := subst.list(n.Init()) init := subst.list(n.Init())
if len(subst.retvars) != 0 && n.List().Len() != 0 { if len(subst.retvars) != 0 && n.List().Len() != 0 {
as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil) as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
@ -1285,6 +1302,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
return ir.NewBlockStmt(base.Pos, init) return ir.NewBlockStmt(base.Pos, init)
case ir.OGOTO: case ir.OGOTO:
n := n.(*ir.BranchStmt)
m := ir.Copy(n).(*ir.BranchStmt) m := ir.Copy(n).(*ir.BranchStmt)
m.SetPos(subst.updatedPos(m.Pos())) m.SetPos(subst.updatedPos(m.Pos()))
m.PtrInit().Set(nil) m.PtrInit().Set(nil)
@ -1293,6 +1311,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
return m return m
case ir.OLABEL: case ir.OLABEL:
n := n.(*ir.LabelStmt)
m := ir.Copy(n).(*ir.LabelStmt) m := ir.Copy(n).(*ir.LabelStmt)
m.SetPos(subst.updatedPos(m.Pos())) m.SetPos(subst.updatedPos(m.Pos()))
m.PtrInit().Set(nil) m.PtrInit().Set(nil)
@ -1365,6 +1384,7 @@ func devirtualizeCall(call *ir.CallExpr) {
x := typecheck(ir.NewSelectorExpr(sel.Pos(), ir.OXDOT, dt, sel.Sym()), ctxExpr|ctxCallee) x := typecheck(ir.NewSelectorExpr(sel.Pos(), ir.OXDOT, dt, sel.Sym()), ctxExpr|ctxCallee)
switch x.Op() { switch x.Op() {
case ir.ODOTMETH: case ir.ODOTMETH:
x := x.(*ir.SelectorExpr)
if base.Flag.LowerM != 0 { if base.Flag.LowerM != 0 {
base.WarnfAt(call.Pos(), "devirtualizing %v to %v", sel, typ) base.WarnfAt(call.Pos(), "devirtualizing %v to %v", sel, typ)
} }
@ -1372,6 +1392,7 @@ func devirtualizeCall(call *ir.CallExpr) {
call.SetLeft(x) call.SetLeft(x)
case ir.ODOTINTER: case ir.ODOTINTER:
// Promoted method from embedded interface-typed field (#42279). // Promoted method from embedded interface-typed field (#42279).
x := x.(*ir.SelectorExpr)
if base.Flag.LowerM != 0 { if base.Flag.LowerM != 0 {
base.WarnfAt(call.Pos(), "partially devirtualizing %v to %v", sel, typ) base.WarnfAt(call.Pos(), "partially devirtualizing %v to %v", sel, typ)
} }

View file

@ -1169,6 +1169,7 @@ func (p *noder) ifStmt(stmt *syntax.IfStmt) ir.Node {
if stmt.Else != nil { if stmt.Else != nil {
e := p.stmt(stmt.Else) e := p.stmt(stmt.Else)
if e.Op() == ir.OBLOCK { if e.Op() == ir.OBLOCK {
e := e.(*ir.BlockStmt)
n.PtrRlist().Set(e.List().Slice()) n.PtrRlist().Set(e.List().Slice())
} else { } else {
n.PtrRlist().Set1(e) n.PtrRlist().Set1(e)
@ -1319,12 +1320,16 @@ func (p *noder) labeledStmt(label *syntax.LabeledStmt, fallOK bool) ir.Node {
if ls != nil { if ls != nil {
switch ls.Op() { switch ls.Op() {
case ir.OFOR: case ir.OFOR:
ls := ls.(*ir.ForStmt)
ls.SetSym(sym) ls.SetSym(sym)
case ir.ORANGE: case ir.ORANGE:
ls := ls.(*ir.RangeStmt)
ls.SetSym(sym) ls.SetSym(sym)
case ir.OSWITCH: case ir.OSWITCH:
ls := ls.(*ir.SwitchStmt)
ls.SetSym(sym) ls.SetSym(sym)
case ir.OSELECT: case ir.OSELECT:
ls := ls.(*ir.SelectStmt)
ls.SetSym(sym) ls.SetSym(sym)
} }
} }
@ -1333,6 +1338,7 @@ func (p *noder) labeledStmt(label *syntax.LabeledStmt, fallOK bool) ir.Node {
l := []ir.Node{lhs} l := []ir.Node{lhs}
if ls != nil { if ls != nil {
if ls.Op() == ir.OBLOCK { if ls.Op() == ir.OBLOCK {
ls := ls.(*ir.BlockStmt)
l = append(l, ls.List().Slice()...) l = append(l, ls.List().Slice()...)
} else { } else {
l = append(l, ls) l = append(l, ls)

View file

@ -135,6 +135,7 @@ func (o *Order) cheapExpr(n ir.Node) ir.Node {
case ir.ONAME, ir.OLITERAL, ir.ONIL: case ir.ONAME, ir.OLITERAL, ir.ONIL:
return n return n
case ir.OLEN, ir.OCAP: case ir.OLEN, ir.OCAP:
n := n.(*ir.UnaryExpr)
l := o.cheapExpr(n.Left()) l := o.cheapExpr(n.Left())
if l == n.Left() { if l == n.Left() {
return n return n
@ -160,6 +161,7 @@ func (o *Order) safeExpr(n ir.Node) ir.Node {
return n return n
case ir.OLEN, ir.OCAP: case ir.OLEN, ir.OCAP:
n := n.(*ir.UnaryExpr)
l := o.safeExpr(n.Left()) l := o.safeExpr(n.Left())
if l == n.Left() { if l == n.Left() {
return n return n
@ -169,6 +171,7 @@ func (o *Order) safeExpr(n ir.Node) ir.Node {
return typecheck(a, ctxExpr) return typecheck(a, ctxExpr)
case ir.ODOT: case ir.ODOT:
n := n.(*ir.SelectorExpr)
l := o.safeExpr(n.Left()) l := o.safeExpr(n.Left())
if l == n.Left() { if l == n.Left() {
return n return n
@ -178,6 +181,7 @@ func (o *Order) safeExpr(n ir.Node) ir.Node {
return typecheck(a, ctxExpr) return typecheck(a, ctxExpr)
case ir.ODOTPTR: case ir.ODOTPTR:
n := n.(*ir.SelectorExpr)
l := o.cheapExpr(n.Left()) l := o.cheapExpr(n.Left())
if l == n.Left() { if l == n.Left() {
return n return n
@ -187,6 +191,7 @@ func (o *Order) safeExpr(n ir.Node) ir.Node {
return typecheck(a, ctxExpr) return typecheck(a, ctxExpr)
case ir.ODEREF: case ir.ODEREF:
n := n.(*ir.StarExpr)
l := o.cheapExpr(n.Left()) l := o.cheapExpr(n.Left())
if l == n.Left() { if l == n.Left() {
return n return n
@ -196,6 +201,7 @@ func (o *Order) safeExpr(n ir.Node) ir.Node {
return typecheck(a, ctxExpr) return typecheck(a, ctxExpr)
case ir.OINDEX, ir.OINDEXMAP: case ir.OINDEX, ir.OINDEXMAP:
n := n.(*ir.IndexExpr)
var l ir.Node var l ir.Node
if n.Left().Type().IsArray() { if n.Left().Type().IsArray() {
l = o.safeExpr(n.Left()) l = o.safeExpr(n.Left())
@ -281,9 +287,11 @@ func mapKeyReplaceStrConv(n ir.Node) bool {
var replaced bool var replaced bool
switch n.Op() { switch n.Op() {
case ir.OBYTES2STR: case ir.OBYTES2STR:
n := n.(*ir.ConvExpr)
n.SetOp(ir.OBYTES2STRTMP) n.SetOp(ir.OBYTES2STRTMP)
replaced = true replaced = true
case ir.OSTRUCTLIT: case ir.OSTRUCTLIT:
n := n.(*ir.CompLitExpr)
for _, elem := range n.List().Slice() { for _, elem := range n.List().Slice() {
elem := elem.(*ir.StructKeyExpr) elem := elem.(*ir.StructKeyExpr)
if mapKeyReplaceStrConv(elem.Left()) { if mapKeyReplaceStrConv(elem.Left()) {
@ -291,6 +299,7 @@ func mapKeyReplaceStrConv(n ir.Node) bool {
} }
} }
case ir.OARRAYLIT: case ir.OARRAYLIT:
n := n.(*ir.CompLitExpr)
for _, elem := range n.List().Slice() { for _, elem := range n.List().Slice() {
if elem.Op() == ir.OKEY { if elem.Op() == ir.OKEY {
elem = elem.(*ir.KeyExpr).Right() elem = elem.(*ir.KeyExpr).Right()
@ -499,6 +508,7 @@ func (o *Order) call(nn ir.Node) {
// by copying it into a temp and marking that temp // by copying it into a temp and marking that temp
// still alive when we pop the temp stack. // still alive when we pop the temp stack.
if arg.Op() == ir.OCONVNOP { if arg.Op() == ir.OCONVNOP {
arg := arg.(*ir.ConvExpr)
if arg.Left().Type().IsUnsafePtr() { if arg.Left().Type().IsUnsafePtr() {
x := o.copyExpr(arg.Left()) x := o.copyExpr(arg.Left())
arg.SetLeft(x) arg.SetLeft(x)
@ -512,6 +522,7 @@ func (o *Order) call(nn ir.Node) {
for i, param := range n.Left().Type().Params().FieldSlice() { for i, param := range n.Left().Type().Params().FieldSlice() {
if param.Note == unsafeUintptrTag || param.Note == uintptrEscapesTag { if param.Note == unsafeUintptrTag || param.Note == uintptrEscapesTag {
if arg := n.List().Index(i); arg.Op() == ir.OSLICELIT { if arg := n.List().Index(i); arg.Op() == ir.OSLICELIT {
arg := arg.(*ir.CompLitExpr)
for _, elt := range arg.List().Slice() { for _, elt := range arg.List().Slice() {
keepAlive(elt) keepAlive(elt)
} }
@ -543,17 +554,20 @@ func (o *Order) mapAssign(n ir.Node) {
base.Fatalf("order.mapAssign %v", n.Op()) base.Fatalf("order.mapAssign %v", n.Op())
case ir.OAS: case ir.OAS:
n := n.(*ir.AssignStmt)
if n.Left().Op() == ir.OINDEXMAP { if n.Left().Op() == ir.OINDEXMAP {
n.SetRight(o.safeMapRHS(n.Right())) n.SetRight(o.safeMapRHS(n.Right()))
} }
o.out = append(o.out, n) o.out = append(o.out, n)
case ir.OASOP: case ir.OASOP:
n := n.(*ir.AssignOpStmt)
if n.Left().Op() == ir.OINDEXMAP { if n.Left().Op() == ir.OINDEXMAP {
n.SetRight(o.safeMapRHS(n.Right())) n.SetRight(o.safeMapRHS(n.Right()))
} }
o.out = append(o.out, n) o.out = append(o.out, n)
case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2MAPR, ir.OAS2FUNC: case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2MAPR, ir.OAS2FUNC:
n := n.(*ir.AssignListStmt)
var post []ir.Node var post []ir.Node
for i, m := range n.List().Slice() { for i, m := range n.List().Slice() {
switch { switch {
@ -583,6 +597,7 @@ func (o *Order) safeMapRHS(r ir.Node) ir.Node {
// Make sure we evaluate the RHS before starting the map insert. // Make sure we evaluate the RHS before starting the map insert.
// We need to make sure the RHS won't panic. See issue 22881. // We need to make sure the RHS won't panic. See issue 22881.
if r.Op() == ir.OAPPEND { if r.Op() == ir.OAPPEND {
r := r.(*ir.CallExpr)
s := r.List().Slice()[1:] s := r.List().Slice()[1:]
for i, n := range s { for i, n := range s {
s[i] = o.cheapExpr(n) s[i] = o.cheapExpr(n)
@ -611,6 +626,7 @@ func (o *Order) stmt(n ir.Node) {
o.out = append(o.out, n) o.out = append(o.out, n)
case ir.OAS: case ir.OAS:
n := n.(*ir.AssignStmt)
t := o.markTemp() t := o.markTemp()
n.SetLeft(o.expr(n.Left(), nil)) n.SetLeft(o.expr(n.Left(), nil))
n.SetRight(o.expr(n.Right(), n.Left())) n.SetRight(o.expr(n.Right(), n.Left()))
@ -618,6 +634,7 @@ func (o *Order) stmt(n ir.Node) {
o.cleanTemp(t) o.cleanTemp(t)
case ir.OASOP: case ir.OASOP:
n := n.(*ir.AssignOpStmt)
t := o.markTemp() t := o.markTemp()
n.SetLeft(o.expr(n.Left(), nil)) n.SetLeft(o.expr(n.Left(), nil))
n.SetRight(o.expr(n.Right(), nil)) n.SetRight(o.expr(n.Right(), nil))
@ -632,6 +649,7 @@ func (o *Order) stmt(n ir.Node) {
l1 := o.safeExpr(n.Left()) l1 := o.safeExpr(n.Left())
l2 := ir.DeepCopy(src.NoXPos, l1) l2 := ir.DeepCopy(src.NoXPos, l1)
if l2.Op() == ir.OINDEXMAP { if l2.Op() == ir.OINDEXMAP {
l2 := l2.(*ir.IndexExpr)
l2.SetIndexMapLValue(false) l2.SetIndexMapLValue(false)
} }
l2 = o.copyExpr(l2) l2 = o.copyExpr(l2)
@ -646,6 +664,7 @@ func (o *Order) stmt(n ir.Node) {
o.cleanTemp(t) o.cleanTemp(t)
case ir.OAS2: case ir.OAS2:
n := n.(*ir.AssignListStmt)
t := o.markTemp() t := o.markTemp()
o.exprList(n.List()) o.exprList(n.List())
o.exprList(n.Rlist()) o.exprList(n.Rlist())
@ -675,10 +694,13 @@ func (o *Order) stmt(n ir.Node) {
switch r := n.Rlist().First(); r.Op() { switch r := n.Rlist().First(); r.Op() {
case ir.ODOTTYPE2: case ir.ODOTTYPE2:
r := r.(*ir.TypeAssertExpr)
r.SetLeft(o.expr(r.Left(), nil)) r.SetLeft(o.expr(r.Left(), nil))
case ir.ORECV: case ir.ORECV:
r := r.(*ir.UnaryExpr)
r.SetLeft(o.expr(r.Left(), nil)) r.SetLeft(o.expr(r.Left(), nil))
case ir.OINDEXMAP: case ir.OINDEXMAP:
r := r.(*ir.IndexExpr)
r.SetLeft(o.expr(r.Left(), nil)) r.SetLeft(o.expr(r.Left(), nil))
r.SetRight(o.expr(r.Right(), nil)) r.SetRight(o.expr(r.Right(), nil))
// See similar conversion for OINDEXMAP below. // See similar conversion for OINDEXMAP below.
@ -693,6 +715,7 @@ func (o *Order) stmt(n ir.Node) {
// Special: does not save n onto out. // Special: does not save n onto out.
case ir.OBLOCK: case ir.OBLOCK:
n := n.(*ir.BlockStmt)
o.stmtList(n.List()) o.stmtList(n.List())
// Special: n->left is not an expression; save as is. // Special: n->left is not an expression; save as is.
@ -709,18 +732,21 @@ func (o *Order) stmt(n ir.Node) {
// Special: handle call arguments. // Special: handle call arguments.
case ir.OCALLFUNC, ir.OCALLINTER, ir.OCALLMETH: case ir.OCALLFUNC, ir.OCALLINTER, ir.OCALLMETH:
n := n.(*ir.CallExpr)
t := o.markTemp() t := o.markTemp()
o.call(n) o.call(n)
o.out = append(o.out, n) o.out = append(o.out, n)
o.cleanTemp(t) o.cleanTemp(t)
case ir.OCLOSE, ir.ORECV: case ir.OCLOSE, ir.ORECV:
n := n.(*ir.UnaryExpr)
t := o.markTemp() t := o.markTemp()
n.SetLeft(o.expr(n.Left(), nil)) n.SetLeft(o.expr(n.Left(), nil))
o.out = append(o.out, n) o.out = append(o.out, n)
o.cleanTemp(t) o.cleanTemp(t)
case ir.OCOPY: case ir.OCOPY:
n := n.(*ir.BinaryExpr)
t := o.markTemp() t := o.markTemp()
n.SetLeft(o.expr(n.Left(), nil)) n.SetLeft(o.expr(n.Left(), nil))
n.SetRight(o.expr(n.Right(), nil)) n.SetRight(o.expr(n.Right(), nil))
@ -728,6 +754,7 @@ func (o *Order) stmt(n ir.Node) {
o.cleanTemp(t) o.cleanTemp(t)
case ir.OPRINT, ir.OPRINTN, ir.ORECOVER: case ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
n := n.(*ir.CallExpr)
t := o.markTemp() t := o.markTemp()
o.exprList(n.List()) o.exprList(n.List())
o.out = append(o.out, n) o.out = append(o.out, n)
@ -735,6 +762,7 @@ func (o *Order) stmt(n ir.Node) {
// Special: order arguments to inner call but not call itself. // Special: order arguments to inner call but not call itself.
case ir.ODEFER, ir.OGO: case ir.ODEFER, ir.OGO:
n := n.(*ir.GoDeferStmt)
t := o.markTemp() t := o.markTemp()
o.init(n.Left()) o.init(n.Left())
o.call(n.Left()) o.call(n.Left())
@ -742,6 +770,7 @@ func (o *Order) stmt(n ir.Node) {
o.cleanTemp(t) o.cleanTemp(t)
case ir.ODELETE: case ir.ODELETE:
n := n.(*ir.CallExpr)
t := o.markTemp() t := o.markTemp()
n.List().SetFirst(o.expr(n.List().First(), nil)) n.List().SetFirst(o.expr(n.List().First(), nil))
n.List().SetSecond(o.expr(n.List().Second(), nil)) n.List().SetSecond(o.expr(n.List().Second(), nil))
@ -752,6 +781,7 @@ func (o *Order) stmt(n ir.Node) {
// Clean temporaries from condition evaluation at // Clean temporaries from condition evaluation at
// beginning of loop body and after for statement. // beginning of loop body and after for statement.
case ir.OFOR: case ir.OFOR:
n := n.(*ir.ForStmt)
t := o.markTemp() t := o.markTemp()
n.SetLeft(o.exprInPlace(n.Left())) n.SetLeft(o.exprInPlace(n.Left()))
n.PtrBody().Prepend(o.cleanTempNoPop(t)...) n.PtrBody().Prepend(o.cleanTempNoPop(t)...)
@ -763,6 +793,7 @@ func (o *Order) stmt(n ir.Node) {
// Clean temporaries from condition at // Clean temporaries from condition at
// beginning of both branches. // beginning of both branches.
case ir.OIF: case ir.OIF:
n := n.(*ir.IfStmt)
t := o.markTemp() t := o.markTemp()
n.SetLeft(o.exprInPlace(n.Left())) n.SetLeft(o.exprInPlace(n.Left()))
n.PtrBody().Prepend(o.cleanTempNoPop(t)...) n.PtrBody().Prepend(o.cleanTempNoPop(t)...)
@ -775,6 +806,7 @@ func (o *Order) stmt(n ir.Node) {
// Special: argument will be converted to interface using convT2E // Special: argument will be converted to interface using convT2E
// so make sure it is an addressable temporary. // so make sure it is an addressable temporary.
case ir.OPANIC: case ir.OPANIC:
n := n.(*ir.UnaryExpr)
t := o.markTemp() t := o.markTemp()
n.SetLeft(o.expr(n.Left(), nil)) n.SetLeft(o.expr(n.Left(), nil))
if !n.Left().Type().IsInterface() { if !n.Left().Type().IsInterface() {
@ -858,6 +890,7 @@ func (o *Order) stmt(n ir.Node) {
o.cleanTemp(t) o.cleanTemp(t)
case ir.ORETURN: case ir.ORETURN:
n := n.(*ir.ReturnStmt)
o.exprList(n.List()) o.exprList(n.List())
o.out = append(o.out, n) o.out = append(o.out, n)
@ -871,6 +904,7 @@ func (o *Order) stmt(n ir.Node) {
// case (if p were nil, then the timing of the fault would // case (if p were nil, then the timing of the fault would
// give this away). // give this away).
case ir.OSELECT: case ir.OSELECT:
n := n.(*ir.SelectStmt)
t := o.markTemp() t := o.markTemp()
for _, ncas := range n.List().Slice() { for _, ncas := range n.List().Slice() {
ncas := ncas.(*ir.CaseStmt) ncas := ncas.(*ir.CaseStmt)
@ -932,6 +966,7 @@ func (o *Order) stmt(n ir.Node) {
orderBlock(ncas.PtrInit(), o.free) orderBlock(ncas.PtrInit(), o.free)
case ir.OSEND: case ir.OSEND:
r := r.(*ir.SendStmt)
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 send") base.Fatalf("ninit on select send")
@ -969,6 +1004,7 @@ func (o *Order) stmt(n ir.Node) {
// Special: value being sent is passed as a pointer; make it addressable. // Special: value being sent is passed as a pointer; make it addressable.
case ir.OSEND: case ir.OSEND:
n := n.(*ir.SendStmt)
t := o.markTemp() t := o.markTemp()
n.SetLeft(o.expr(n.Left(), nil)) n.SetLeft(o.expr(n.Left(), nil))
n.SetRight(o.expr(n.Right(), nil)) n.SetRight(o.expr(n.Right(), nil))
@ -1100,6 +1136,7 @@ func (o *Order) expr1(n, lhs ir.Node) ir.Node {
if haslit && hasbyte { if haslit && hasbyte {
for _, n2 := range n.List().Slice() { for _, n2 := range n.List().Slice() {
if n2.Op() == ir.OBYTES2STR { if n2.Op() == ir.OBYTES2STR {
n2 := n2.(*ir.ConvExpr)
n2.SetOp(ir.OBYTES2STRTMP) n2.SetOp(ir.OBYTES2STRTMP)
} }
} }
@ -1107,6 +1144,7 @@ func (o *Order) expr1(n, lhs ir.Node) ir.Node {
return n return n
case ir.OINDEXMAP: case ir.OINDEXMAP:
n := n.(*ir.IndexExpr)
n.SetLeft(o.expr(n.Left(), nil)) n.SetLeft(o.expr(n.Left(), nil))
n.SetRight(o.expr(n.Right(), nil)) n.SetRight(o.expr(n.Right(), nil))
needCopy := false needCopy := false
@ -1134,6 +1172,7 @@ func (o *Order) expr1(n, lhs ir.Node) ir.Node {
// concrete type (not interface) argument might need an addressable // concrete type (not interface) argument might need an addressable
// temporary to pass to the runtime conversion routine. // temporary to pass to the runtime conversion routine.
case ir.OCONVIFACE: case ir.OCONVIFACE:
n := n.(*ir.ConvExpr)
n.SetLeft(o.expr(n.Left(), nil)) n.SetLeft(o.expr(n.Left(), nil))
if n.Left().Type().IsInterface() { if n.Left().Type().IsInterface() {
return n return n
@ -1147,6 +1186,7 @@ func (o *Order) expr1(n, lhs ir.Node) ir.Node {
return n return n
case ir.OCONVNOP: case ir.OCONVNOP:
n := n.(*ir.ConvExpr)
if n.Type().IsKind(types.TUNSAFEPTR) && n.Left().Type().IsKind(types.TUINTPTR) && (n.Left().Op() == ir.OCALLFUNC || n.Left().Op() == ir.OCALLINTER || n.Left().Op() == ir.OCALLMETH) { if n.Type().IsKind(types.TUNSAFEPTR) && n.Left().Type().IsKind(types.TUINTPTR) && (n.Left().Op() == ir.OCALLFUNC || n.Left().Op() == ir.OCALLINTER || n.Left().Op() == ir.OCALLMETH) {
call := n.Left().(*ir.CallExpr) call := n.Left().(*ir.CallExpr)
// When reordering unsafe.Pointer(f()) into a separate // When reordering unsafe.Pointer(f()) into a separate
@ -1172,6 +1212,7 @@ func (o *Order) expr1(n, lhs ir.Node) ir.Node {
// } // }
// ... = r // ... = r
n := n.(*ir.LogicalExpr)
r := o.newTemp(n.Type(), false) r := o.newTemp(n.Type(), false)
// Evaluate left-hand side. // Evaluate left-hand side.
@ -1233,6 +1274,7 @@ func (o *Order) expr1(n, lhs ir.Node) ir.Node {
case ir.OAPPEND: case ir.OAPPEND:
// Check for append(x, make([]T, y)...) . // Check for append(x, make([]T, y)...) .
n := n.(*ir.CallExpr)
if isAppendOfMake(n) { if isAppendOfMake(n) {
n.List().SetFirst(o.expr(n.List().First(), nil)) // order x n.List().SetFirst(o.expr(n.List().First(), nil)) // order x
mk := n.List().Second().(*ir.MakeExpr) mk := n.List().Second().(*ir.MakeExpr)
@ -1247,6 +1289,7 @@ func (o *Order) expr1(n, lhs ir.Node) ir.Node {
return n return n
case ir.OSLICE, ir.OSLICEARR, ir.OSLICESTR, ir.OSLICE3, ir.OSLICE3ARR: case ir.OSLICE, ir.OSLICEARR, ir.OSLICESTR, ir.OSLICE3, ir.OSLICE3ARR:
n := n.(*ir.SliceExpr)
n.SetLeft(o.expr(n.Left(), nil)) n.SetLeft(o.expr(n.Left(), nil))
low, high, max := n.SliceBounds() low, high, max := n.SliceBounds()
low = o.expr(low, nil) low = o.expr(low, nil)
@ -1287,6 +1330,7 @@ func (o *Order) expr1(n, lhs ir.Node) ir.Node {
return n return n
case ir.ODOTTYPE, ir.ODOTTYPE2: case ir.ODOTTYPE, ir.ODOTTYPE2:
n := n.(*ir.TypeAssertExpr)
n.SetLeft(o.expr(n.Left(), nil)) n.SetLeft(o.expr(n.Left(), nil))
if !isdirectiface(n.Type()) || instrumenting { if !isdirectiface(n.Type()) || instrumenting {
return o.copyExprClear(n) return o.copyExprClear(n)
@ -1294,10 +1338,12 @@ func (o *Order) expr1(n, lhs ir.Node) ir.Node {
return n return n
case ir.ORECV: case ir.ORECV:
n := n.(*ir.UnaryExpr)
n.SetLeft(o.expr(n.Left(), nil)) n.SetLeft(o.expr(n.Left(), nil))
return o.copyExprClear(n) return o.copyExprClear(n)
case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE: case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
n := n.(*ir.BinaryExpr)
n.SetLeft(o.expr(n.Left(), nil)) n.SetLeft(o.expr(n.Left(), nil))
n.SetRight(o.expr(n.Right(), nil)) n.SetRight(o.expr(n.Right(), nil))
@ -1338,6 +1384,7 @@ func (o *Order) expr1(n, lhs ir.Node) ir.Node {
// Without this special case, order would otherwise compute all // Without this special case, order would otherwise compute all
// the keys and values before storing any of them to the map. // the keys and values before storing any of them to the map.
// See issue 26552. // See issue 26552.
n := n.(*ir.CompLitExpr)
entries := n.List().Slice() entries := n.List().Slice()
statics := entries[:0] statics := entries[:0]
var dynamics []*ir.KeyExpr var dynamics []*ir.KeyExpr

View file

@ -81,6 +81,7 @@ func (v *bottomUpVisitor) visit(n *ir.Func) uint32 {
ir.Visit(n, func(n ir.Node) { ir.Visit(n, func(n ir.Node) {
switch n.Op() { switch n.Op() {
case ir.ONAME: case ir.ONAME:
n := n.(*ir.Name)
if n.Class() == ir.PFUNC { if n.Class() == ir.PFUNC {
if n != nil && n.Name().Defn != nil { if n != nil && n.Name().Defn != nil {
if m := v.visit(n.Name().Defn.(*ir.Func)); m < min { if m := v.visit(n.Name().Defn.(*ir.Func)); m < min {
@ -89,6 +90,7 @@ func (v *bottomUpVisitor) visit(n *ir.Func) uint32 {
} }
} }
case ir.OMETHEXPR: case ir.OMETHEXPR:
n := n.(*ir.MethodExpr)
fn := methodExprName(n) fn := methodExprName(n)
if fn != nil && fn.Defn != nil { if fn != nil && fn.Defn != nil {
if m := v.visit(fn.Defn.(*ir.Func)); m < min { if m := v.visit(fn.Defn.(*ir.Func)); m < min {
@ -96,6 +98,7 @@ func (v *bottomUpVisitor) visit(n *ir.Func) uint32 {
} }
} }
case ir.ODOTMETH: case ir.ODOTMETH:
n := n.(*ir.SelectorExpr)
fn := methodExprName(n) fn := methodExprName(n)
if fn != nil && fn.Op() == ir.ONAME && fn.Class() == ir.PFUNC && fn.Defn != nil { if fn != nil && fn.Op() == ir.ONAME && fn.Class() == ir.PFUNC && fn.Defn != nil {
if m := v.visit(fn.Defn.(*ir.Func)); m < min { if m := v.visit(fn.Defn.(*ir.Func)); m < min {
@ -103,6 +106,7 @@ func (v *bottomUpVisitor) visit(n *ir.Func) uint32 {
} }
} }
case ir.OCALLPART: case ir.OCALLPART:
n := n.(*ir.CallPartExpr)
fn := ir.AsNode(callpartMethod(n).Nname) fn := ir.AsNode(callpartMethod(n).Nname)
if fn != nil && fn.Op() == ir.ONAME { if fn != nil && fn.Op() == ir.ONAME {
if fn := fn.(*ir.Name); fn.Class() == ir.PFUNC && fn.Name().Defn != nil { if fn := fn.(*ir.Name); fn.Class() == ir.PFUNC && fn.Name().Defn != nil {

View file

@ -56,7 +56,9 @@ func typecheckselect(sel *ir.SelectStmt) {
// convert x = <-c into x, _ = <-c // convert x = <-c into x, _ = <-c
// remove implicit conversions; the eventual assignment // remove implicit conversions; the eventual assignment
// will reintroduce them. // will reintroduce them.
n := n.(*ir.AssignStmt)
if r := n.Right(); r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE { if r := n.Right(); r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE {
r := r.(*ir.ConvExpr)
if r.Implicit() { if r.Implicit() {
n.SetRight(r.Left()) n.SetRight(r.Left())
} }
@ -68,6 +70,7 @@ func typecheckselect(sel *ir.SelectStmt) {
oselrecv2(n.Left(), n.Right(), n.Colas()) oselrecv2(n.Left(), n.Right(), n.Colas())
case ir.OAS2RECV: case ir.OAS2RECV:
n := n.(*ir.AssignListStmt)
if n.Rlist().First().Op() != ir.ORECV { 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
@ -76,6 +79,7 @@ func typecheckselect(sel *ir.SelectStmt) {
case ir.ORECV: case ir.ORECV:
// convert <-c into _, _ = <-c // convert <-c into _, _ = <-c
n := n.(*ir.UnaryExpr)
oselrecv2(ir.BlankNode, n, false) oselrecv2(ir.BlankNode, n, false)
case ir.OSEND: case ir.OSEND:
@ -162,10 +166,12 @@ func walkselectcases(cases ir.Nodes) []ir.Node {
} }
switch n.Op() { switch n.Op() {
case ir.OSEND: case ir.OSEND:
n := n.(*ir.SendStmt)
n.SetRight(nodAddr(n.Right())) n.SetRight(nodAddr(n.Right()))
n.SetRight(typecheck(n.Right(), ctxExpr)) n.SetRight(typecheck(n.Right(), ctxExpr))
case ir.OSELRECV2: case ir.OSELRECV2:
n := n.(*ir.AssignListStmt)
if !ir.IsBlank(n.List().First()) { if !ir.IsBlank(n.List().First()) {
n.List().SetIndex(0, nodAddr(n.List().First())) n.List().SetIndex(0, nodAddr(n.List().First()))
n.List().SetIndex(0, typecheck(n.List().First(), ctxExpr)) n.List().SetIndex(0, typecheck(n.List().First(), ctxExpr))
@ -191,10 +197,12 @@ 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 }
n := n.(*ir.SendStmt)
ch := n.Left() ch := n.Left()
call = 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.OSELRECV2: case ir.OSELRECV2:
n := n.(*ir.AssignListStmt)
recv := n.Rlist().First().(*ir.UnaryExpr) recv := n.Rlist().First().(*ir.UnaryExpr)
ch := recv.Left() ch := recv.Left()
elem := n.List().First() elem := n.List().First()
@ -261,11 +269,13 @@ func walkselectcases(cases ir.Nodes) []ir.Node {
default: default:
base.Fatalf("select %v", n.Op()) base.Fatalf("select %v", n.Op())
case ir.OSEND: case ir.OSEND:
n := n.(*ir.SendStmt)
i = nsends i = nsends
nsends++ nsends++
c = n.Left() c = n.Left()
elem = n.Right() elem = n.Right()
case ir.OSELRECV2: case ir.OSELRECV2:
n := n.(*ir.AssignListStmt)
nrecvs++ nrecvs++
i = ncas - nrecvs i = ncas - nrecvs
recv := n.Rlist().First().(*ir.UnaryExpr) recv := n.Rlist().First().(*ir.UnaryExpr)
@ -323,6 +333,7 @@ func walkselectcases(cases ir.Nodes) []ir.Node {
r := ir.NewIfStmt(base.Pos, cond, nil, nil) r := ir.NewIfStmt(base.Pos, cond, nil, nil)
if n := cas.Left(); n != nil && n.Op() == ir.OSELRECV2 { if n := cas.Left(); n != nil && n.Op() == ir.OSELRECV2 {
n := n.(*ir.AssignListStmt)
if !ir.IsBlank(n.List().Second()) { if !ir.IsBlank(n.List().Second()) {
x := ir.NewAssignStmt(base.Pos, n.List().Second(), recvOK) x := ir.NewAssignStmt(base.Pos, n.List().Second(), recvOK)
r.PtrBody().Append(typecheck(x, ctxStmt)) r.PtrBody().Append(typecheck(x, ctxStmt))

View file

@ -127,6 +127,7 @@ func (s *InitSchedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *type
return true return true
case ir.OADDR: case ir.OADDR:
r := r.(*ir.AddrExpr)
if a := r.Left(); a.Op() == ir.ONAME { if a := r.Left(); a.Op() == ir.ONAME {
a := a.(*ir.Name) a := a.(*ir.Name)
addrsym(l, loff, a, 0) addrsym(l, loff, a, 0)
@ -134,6 +135,7 @@ func (s *InitSchedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *type
} }
case ir.OPTRLIT: case ir.OPTRLIT:
r := r.(*ir.AddrExpr)
switch r.Left().Op() { switch r.Left().Op() {
case ir.OARRAYLIT, ir.OSLICELIT, ir.OSTRUCTLIT, ir.OMAPLIT: case ir.OARRAYLIT, ir.OSLICELIT, ir.OSTRUCTLIT, ir.OMAPLIT:
// copy pointer // copy pointer
@ -148,6 +150,7 @@ func (s *InitSchedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *type
return true return true
case ir.OARRAYLIT, ir.OSTRUCTLIT: case ir.OARRAYLIT, ir.OSTRUCTLIT:
r := r.(*ir.CompLitExpr)
p := s.initplans[r] p := s.initplans[r]
for i := range p.E { for i := range p.E {
e := &p.E[i] e := &p.E[i]
@ -202,6 +205,7 @@ func (s *InitSchedule) staticassign(l *ir.Name, loff int64, r ir.Node, typ *type
return true return true
case ir.OADDR: case ir.OADDR:
r := r.(*ir.AddrExpr)
if name, offset, ok := stataddr(r.Left()); ok { if name, offset, ok := stataddr(r.Left()); ok {
addrsym(l, loff, name, offset) addrsym(l, loff, name, offset)
return true return true
@ -209,6 +213,7 @@ func (s *InitSchedule) staticassign(l *ir.Name, loff int64, r ir.Node, typ *type
fallthrough fallthrough
case ir.OPTRLIT: case ir.OPTRLIT:
r := r.(*ir.AddrExpr)
switch r.Left().Op() { switch r.Left().Op() {
case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT, ir.OSTRUCTLIT: case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT, ir.OSTRUCTLIT:
// Init pointer. // Init pointer.
@ -226,6 +231,7 @@ func (s *InitSchedule) staticassign(l *ir.Name, loff int64, r ir.Node, typ *type
//dump("not static ptrlit", r); //dump("not static ptrlit", r);
case ir.OSTR2BYTES: case ir.OSTR2BYTES:
r := r.(*ir.ConvExpr)
if l.Class() == ir.PEXTERN && r.Left().Op() == ir.OLITERAL { if l.Class() == ir.PEXTERN && r.Left().Op() == ir.OLITERAL {
sval := ir.StringVal(r.Left()) sval := ir.StringVal(r.Left())
slicebytes(l, loff, sval) slicebytes(l, loff, sval)
@ -247,6 +253,7 @@ func (s *InitSchedule) staticassign(l *ir.Name, loff int64, r ir.Node, typ *type
fallthrough fallthrough
case ir.OARRAYLIT, ir.OSTRUCTLIT: case ir.OARRAYLIT, ir.OSTRUCTLIT:
r := r.(*ir.CompLitExpr)
s.initplan(r) s.initplan(r)
p := s.initplans[r] p := s.initplans[r]
@ -287,6 +294,7 @@ func (s *InitSchedule) staticassign(l *ir.Name, loff int64, r ir.Node, typ *type
// If you change something here, change it there, and vice versa. // If you change something here, change it there, and vice versa.
// Determine the underlying concrete type and value we are converting from. // Determine the underlying concrete type and value we are converting from.
r := r.(*ir.ConvExpr)
val := ir.Node(r) val := ir.Node(r)
for val.Op() == ir.OCONVIFACE { for val.Op() == ir.OCONVIFACE {
val = val.(*ir.ConvExpr).Left() val = val.(*ir.ConvExpr).Left()
@ -467,6 +475,7 @@ func isStaticCompositeLiteral(n ir.Node) bool {
case ir.OSLICELIT: case ir.OSLICELIT:
return false return false
case ir.OARRAYLIT: case ir.OARRAYLIT:
n := n.(*ir.CompLitExpr)
for _, r := range n.List().Slice() { for _, r := range n.List().Slice() {
if r.Op() == ir.OKEY { if r.Op() == ir.OKEY {
r = r.(*ir.KeyExpr).Right() r = r.(*ir.KeyExpr).Right()
@ -477,6 +486,7 @@ func isStaticCompositeLiteral(n ir.Node) bool {
} }
return true return true
case ir.OSTRUCTLIT: case ir.OSTRUCTLIT:
n := n.(*ir.CompLitExpr)
for _, r := range n.List().Slice() { for _, r := range n.List().Slice() {
r := r.(*ir.StructKeyExpr) r := r.(*ir.StructKeyExpr)
if !isStaticCompositeLiteral(r.Left()) { if !isStaticCompositeLiteral(r.Left()) {
@ -488,6 +498,7 @@ func isStaticCompositeLiteral(n ir.Node) bool {
return true return true
case ir.OCONVIFACE: case ir.OCONVIFACE:
// See staticassign's OCONVIFACE case for comments. // See staticassign's OCONVIFACE case for comments.
n := n.(*ir.ConvExpr)
val := ir.Node(n) val := ir.Node(n)
for val.Op() == ir.OCONVIFACE { for val.Op() == ir.OCONVIFACE {
val = val.(*ir.ConvExpr).Left() val = val.(*ir.ConvExpr).Left()
@ -865,6 +876,7 @@ func anylit(n ir.Node, var_ ir.Node, init *ir.Nodes) {
base.Fatalf("anylit: not lit, op=%v node=%v", n.Op(), n) base.Fatalf("anylit: not lit, op=%v node=%v", n.Op(), n)
case ir.ONAME: case ir.ONAME:
n := n.(*ir.Name)
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, n)) appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, n))
case ir.OMETHEXPR: case ir.OMETHEXPR:
@ -872,6 +884,7 @@ func anylit(n ir.Node, var_ ir.Node, init *ir.Nodes) {
anylit(n.FuncName(), var_, init) anylit(n.FuncName(), var_, init)
case ir.OPTRLIT: case ir.OPTRLIT:
n := n.(*ir.AddrExpr)
if !t.IsPtr() { if !t.IsPtr() {
base.Fatalf("anylit: not ptr") base.Fatalf("anylit: not ptr")
} }
@ -1001,6 +1014,7 @@ func stataddr(n ir.Node) (name *ir.Name, offset int64, ok bool) {
return stataddr(n.FuncName()) return stataddr(n.FuncName())
case ir.ODOT: case ir.ODOT:
n := n.(*ir.SelectorExpr)
if name, offset, ok = stataddr(n.Left()); !ok { if name, offset, ok = stataddr(n.Left()); !ok {
break break
} }
@ -1008,6 +1022,7 @@ func stataddr(n ir.Node) (name *ir.Name, offset int64, ok bool) {
return name, offset, true return name, offset, true
case ir.OINDEX: case ir.OINDEX:
n := n.(*ir.IndexExpr)
if n.Left().Type().IsSlice() { if n.Left().Type().IsSlice() {
break break
} }
@ -1041,6 +1056,7 @@ func (s *InitSchedule) initplan(n ir.Node) {
base.Fatalf("initplan") base.Fatalf("initplan")
case ir.OARRAYLIT, ir.OSLICELIT: case ir.OARRAYLIT, ir.OSLICELIT:
n := n.(*ir.CompLitExpr)
var k int64 var k int64
for _, a := range n.List().Slice() { for _, a := range n.List().Slice() {
if a.Op() == ir.OKEY { if a.Op() == ir.OKEY {
@ -1056,6 +1072,7 @@ func (s *InitSchedule) initplan(n ir.Node) {
} }
case ir.OSTRUCTLIT: case ir.OSTRUCTLIT:
n := n.(*ir.CompLitExpr)
for _, a := range n.List().Slice() { for _, a := range n.List().Slice() {
if a.Op() != ir.OSTRUCTKEY { if a.Op() != ir.OSTRUCTKEY {
base.Fatalf("initplan structlit") base.Fatalf("initplan structlit")
@ -1068,6 +1085,7 @@ func (s *InitSchedule) initplan(n ir.Node) {
} }
case ir.OMAPLIT: case ir.OMAPLIT:
n := n.(*ir.CompLitExpr)
for _, a := range n.List().Slice() { for _, a := range n.List().Slice() {
if a.Op() != ir.OKEY { if a.Op() != ir.OKEY {
base.Fatalf("initplan maplit") base.Fatalf("initplan maplit")
@ -1116,6 +1134,7 @@ func isZero(n ir.Node) bool {
} }
case ir.OARRAYLIT: case ir.OARRAYLIT:
n := n.(*ir.CompLitExpr)
for _, n1 := range n.List().Slice() { for _, n1 := range n.List().Slice() {
if n1.Op() == ir.OKEY { if n1.Op() == ir.OKEY {
n1 = n1.(*ir.KeyExpr).Right() n1 = n1.(*ir.KeyExpr).Right()
@ -1127,6 +1146,7 @@ func isZero(n ir.Node) bool {
return true return true
case ir.OSTRUCTLIT: case ir.OSTRUCTLIT:
n := n.(*ir.CompLitExpr)
for _, n1 := range n.List().Slice() { for _, n1 := range n.List().Slice() {
n1 := n1.(*ir.StructKeyExpr) n1 := n1.(*ir.StructKeyExpr)
if !isZero(n1.Left()) { if !isZero(n1.Left()) {

View file

@ -1150,6 +1150,7 @@ func (s *state) stmt(n ir.Node) {
switch n.Op() { switch n.Op() {
case ir.OBLOCK: case ir.OBLOCK:
n := n.(*ir.BlockStmt)
s.stmtList(n.List()) s.stmtList(n.List())
// No-ops // No-ops
@ -1180,6 +1181,7 @@ func (s *state) stmt(n ir.Node) {
} }
} }
case ir.ODEFER: case ir.ODEFER:
n := n.(*ir.GoDeferStmt)
if base.Debug.Defer > 0 { if base.Debug.Defer > 0 {
var defertype string var defertype string
if s.hasOpenDefers { if s.hasOpenDefers {
@ -1201,9 +1203,11 @@ func (s *state) stmt(n ir.Node) {
s.callResult(n.Left().(*ir.CallExpr), d) s.callResult(n.Left().(*ir.CallExpr), d)
} }
case ir.OGO: case ir.OGO:
n := n.(*ir.GoDeferStmt)
s.callResult(n.Left().(*ir.CallExpr), callGo) s.callResult(n.Left().(*ir.CallExpr), callGo)
case ir.OAS2DOTTYPE: case ir.OAS2DOTTYPE:
n := n.(*ir.AssignListStmt)
res, resok := s.dottype(n.Rlist().First().(*ir.TypeAssertExpr), true) res, resok := s.dottype(n.Rlist().First().(*ir.TypeAssertExpr), true)
deref := false deref := false
if !canSSAType(n.Rlist().First().Type()) { if !canSSAType(n.Rlist().First().Type()) {
@ -1226,6 +1230,7 @@ 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.
n := n.(*ir.AssignListStmt)
call := n.Rlist().First().(*ir.CallExpr) call := n.Rlist().First().(*ir.CallExpr)
if !IsIntrinsicCall(call) { if !IsIntrinsicCall(call) {
s.Fatalf("non-intrinsic AS2FUNC not expanded %v", call) s.Fatalf("non-intrinsic AS2FUNC not expanded %v", call)
@ -1238,11 +1243,13 @@ func (s *state) stmt(n ir.Node) {
return return
case ir.ODCL: case ir.ODCL:
n := n.(*ir.Decl)
if n.Left().(*ir.Name).Class() == ir.PAUTOHEAP { if n.Left().(*ir.Name).Class() == ir.PAUTOHEAP {
s.Fatalf("DCL %v", n) s.Fatalf("DCL %v", n)
} }
case ir.OLABEL: case ir.OLABEL:
n := n.(*ir.LabelStmt)
sym := n.Sym() sym := n.Sym()
lab := s.label(sym) lab := s.label(sym)
@ -1260,6 +1267,7 @@ func (s *state) stmt(n ir.Node) {
s.startBlock(lab.target) s.startBlock(lab.target)
case ir.OGOTO: case ir.OGOTO:
n := n.(*ir.BranchStmt)
sym := n.Sym() sym := n.Sym()
lab := s.label(sym) lab := s.label(sym)
@ -1272,6 +1280,7 @@ func (s *state) stmt(n ir.Node) {
b.AddEdgeTo(lab.target) b.AddEdgeTo(lab.target)
case ir.OAS: case ir.OAS:
n := n.(*ir.AssignStmt)
if n.Left() == n.Right() && n.Left().Op() == ir.ONAME { if n.Left() == n.Right() && n.Left().Op() == ir.ONAME {
// An x=x assignment. No point in doing anything // An x=x assignment. No point in doing anything
// here. In addition, skipping this assignment // here. In addition, skipping this assignment
@ -1356,6 +1365,7 @@ func (s *state) stmt(n ir.Node) {
if rhs != nil && (rhs.Op() == ir.OSLICE || rhs.Op() == ir.OSLICE3 || rhs.Op() == ir.OSLICESTR) && samesafeexpr(rhs.(*ir.SliceExpr).Left(), n.Left()) { if rhs != nil && (rhs.Op() == ir.OSLICE || rhs.Op() == ir.OSLICE3 || rhs.Op() == ir.OSLICESTR) && samesafeexpr(rhs.(*ir.SliceExpr).Left(), n.Left()) {
// We're assigning a slicing operation back to its source. // We're assigning a slicing operation back to its source.
// Don't write back fields we aren't changing. See issue #14855. // Don't write back fields we aren't changing. See issue #14855.
rhs := rhs.(*ir.SliceExpr)
i, j, k := rhs.SliceBounds() i, j, k := rhs.SliceBounds()
if i != nil && (i.Op() == ir.OLITERAL && i.Val().Kind() == constant.Int && ir.Int64Val(i) == 0) { if i != nil && (i.Op() == ir.OLITERAL && i.Val().Kind() == constant.Int && ir.Int64Val(i) == 0) {
// [0:...] is the same as [:...] // [0:...] is the same as [:...]
@ -1385,6 +1395,7 @@ func (s *state) stmt(n ir.Node) {
s.assign(n.Left(), r, deref, skip) s.assign(n.Left(), r, deref, skip)
case ir.OIF: case ir.OIF:
n := n.(*ir.IfStmt)
if ir.IsConst(n.Left(), constant.Bool) { if ir.IsConst(n.Left(), constant.Bool) {
s.stmtList(n.Left().Init()) s.stmtList(n.Left().Init())
if ir.BoolVal(n.Left()) { if ir.BoolVal(n.Left()) {
@ -1431,16 +1442,19 @@ func (s *state) stmt(n ir.Node) {
s.startBlock(bEnd) s.startBlock(bEnd)
case ir.ORETURN: case ir.ORETURN:
n := n.(*ir.ReturnStmt)
s.stmtList(n.List()) s.stmtList(n.List())
b := s.exit() b := s.exit()
b.Pos = s.lastPos.WithIsStmt() b.Pos = s.lastPos.WithIsStmt()
case ir.ORETJMP: case ir.ORETJMP:
n := n.(*ir.BranchStmt)
b := s.exit() b := s.exit()
b.Kind = ssa.BlockRetJmp // override BlockRet b.Kind = ssa.BlockRetJmp // override BlockRet
b.Aux = callTargetLSym(n.Sym(), s.curfn.LSym) b.Aux = callTargetLSym(n.Sym(), s.curfn.LSym)
case ir.OCONTINUE, ir.OBREAK: case ir.OCONTINUE, ir.OBREAK:
n := n.(*ir.BranchStmt)
var to *ssa.Block var to *ssa.Block
if n.Sym() == nil { if n.Sym() == nil {
// plain break/continue // plain break/continue
@ -1472,6 +1486,7 @@ func (s *state) stmt(n ir.Node) {
// //
// OFORUNTIL: for Ninit; Left; Right; List { Nbody } // OFORUNTIL: for Ninit; Left; Right; List { Nbody }
// => body: { Nbody }; incr: Right; if Left { lateincr: List; goto body }; end: // => body: { Nbody }; incr: Right; if Left { lateincr: List; goto body }; end:
n := n.(*ir.ForStmt)
bCond := s.f.NewBlock(ssa.BlockPlain) bCond := s.f.NewBlock(ssa.BlockPlain)
bBody := s.f.NewBlock(ssa.BlockPlain) bBody := s.f.NewBlock(ssa.BlockPlain)
bIncr := s.f.NewBlock(ssa.BlockPlain) bIncr := s.f.NewBlock(ssa.BlockPlain)
@ -1600,6 +1615,7 @@ func (s *state) stmt(n ir.Node) {
s.startBlock(bEnd) s.startBlock(bEnd)
case ir.OVARDEF: case ir.OVARDEF:
n := n.(*ir.UnaryExpr)
if !s.canSSA(n.Left()) { if !s.canSSA(n.Left()) {
s.vars[memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, n.Left().(*ir.Name), s.mem(), false) s.vars[memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, n.Left().(*ir.Name), s.mem(), false)
} }
@ -1608,12 +1624,14 @@ func (s *state) stmt(n ir.Node) {
// We only care about liveness info at call sites, so putting the // We only care about liveness info at call sites, so putting the
// varkill in the store chain is enough to keep it correctly ordered // varkill in the store chain is enough to keep it correctly ordered
// with respect to call ops. // with respect to call ops.
n := n.(*ir.UnaryExpr)
if !s.canSSA(n.Left()) { if !s.canSSA(n.Left()) {
s.vars[memVar] = s.newValue1Apos(ssa.OpVarKill, types.TypeMem, n.Left().(*ir.Name), s.mem(), false) s.vars[memVar] = s.newValue1Apos(ssa.OpVarKill, types.TypeMem, n.Left().(*ir.Name), s.mem(), false)
} }
case ir.OVARLIVE: case ir.OVARLIVE:
// Insert a varlive op to record that a variable is still live. // Insert a varlive op to record that a variable is still live.
n := n.(*ir.UnaryExpr)
v := n.Left().(*ir.Name) v := n.Left().(*ir.Name)
if !v.Addrtaken() { if !v.Addrtaken() {
s.Fatalf("VARLIVE variable %v must have Addrtaken set", v) s.Fatalf("VARLIVE variable %v must have Addrtaken set", v)
@ -1626,10 +1644,12 @@ func (s *state) stmt(n ir.Node) {
s.vars[memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, v, s.mem()) s.vars[memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, v, s.mem())
case ir.OCHECKNIL: case ir.OCHECKNIL:
n := n.(*ir.UnaryExpr)
p := s.expr(n.Left()) p := s.expr(n.Left())
s.nilCheck(p) s.nilCheck(p)
case ir.OINLMARK: case ir.OINLMARK:
n := n.(*ir.InlineMarkStmt)
s.newValue1I(ssa.OpInlMark, types.TypeVoid, n.Offset(), s.mem()) s.newValue1I(ssa.OpInlMark, types.TypeVoid, n.Offset(), s.mem())
default: default:
@ -2097,16 +2117,19 @@ func (s *state) expr(n ir.Node) *ssa.Value {
s.stmtList(n.Init()) s.stmtList(n.Init())
switch n.Op() { switch n.Op() {
case ir.OBYTES2STRTMP: case ir.OBYTES2STRTMP:
n := n.(*ir.ConvExpr)
slice := s.expr(n.Left()) slice := s.expr(n.Left())
ptr := s.newValue1(ssa.OpSlicePtr, s.f.Config.Types.BytePtr, slice) ptr := s.newValue1(ssa.OpSlicePtr, s.f.Config.Types.BytePtr, slice)
len := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], slice) len := s.newValue1(ssa.OpSliceLen, types.Types[types.TINT], slice)
return s.newValue2(ssa.OpStringMake, n.Type(), ptr, len) return s.newValue2(ssa.OpStringMake, n.Type(), ptr, len)
case ir.OSTR2BYTESTMP: case ir.OSTR2BYTESTMP:
n := n.(*ir.ConvExpr)
str := s.expr(n.Left()) str := s.expr(n.Left())
ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, str) ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, str)
len := s.newValue1(ssa.OpStringLen, types.Types[types.TINT], str) len := s.newValue1(ssa.OpStringLen, types.Types[types.TINT], str)
return s.newValue3(ssa.OpSliceMake, n.Type(), ptr, len, len) return s.newValue3(ssa.OpSliceMake, n.Type(), ptr, len, len)
case ir.OCFUNC: case ir.OCFUNC:
n := n.(*ir.UnaryExpr)
aux := n.Left().Sym().Linksym() aux := n.Left().Sym().Linksym()
return s.entryNewValue1A(ssa.OpAddr, n.Type(), aux, s.sb) return s.entryNewValue1A(ssa.OpAddr, n.Type(), aux, s.sb)
case ir.OMETHEXPR: case ir.OMETHEXPR:
@ -2114,6 +2137,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
sym := funcsym(n.FuncName().Sym()).Linksym() sym := funcsym(n.FuncName().Sym()).Linksym()
return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type()), sym, s.sb) return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type()), sym, s.sb)
case ir.ONAME: case ir.ONAME:
n := n.(*ir.Name)
if n.Class() == ir.PFUNC { if n.Class() == ir.PFUNC {
// "value" of a function is the address of the function's closure // "value" of a function is the address of the function's closure
sym := funcsym(n.Sym()).Linksym() sym := funcsym(n.Sym()).Linksym()
@ -2135,6 +2159,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
addr := s.addr(n) addr := s.addr(n)
return s.load(n.Type(), addr) return s.load(n.Type(), addr)
case ir.ONIL: case ir.ONIL:
n := n.(*ir.NilExpr)
t := n.Type() t := n.Type()
switch { switch {
case t.IsSlice(): case t.IsSlice():
@ -2203,6 +2228,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
return nil return nil
} }
case ir.OCONVNOP: case ir.OCONVNOP:
n := n.(*ir.ConvExpr)
to := n.Type() to := n.Type()
from := n.Left().Type() from := n.Left().Type()
@ -2271,6 +2297,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
return v return v
case ir.OCONV: case ir.OCONV:
n := n.(*ir.ConvExpr)
x := s.expr(n.Left()) x := s.expr(n.Left())
ft := n.Left().Type() // from type ft := n.Left().Type() // from type
tt := n.Type() // to type tt := n.Type() // to type
@ -2448,6 +2475,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
// binary ops // binary ops
case ir.OLT, ir.OEQ, ir.ONE, ir.OLE, ir.OGE, ir.OGT: case ir.OLT, ir.OEQ, ir.ONE, ir.OLE, ir.OGE, ir.OGT:
n := n.(*ir.BinaryExpr)
a := s.expr(n.Left()) a := s.expr(n.Left())
b := s.expr(n.Right()) b := s.expr(n.Right())
if n.Left().Type().IsComplex() { if n.Left().Type().IsComplex() {
@ -2481,6 +2509,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
// integer comparison // integer comparison
return s.newValue2(s.ssaOp(op, n.Left().Type()), types.Types[types.TBOOL], a, b) return s.newValue2(s.ssaOp(op, n.Left().Type()), types.Types[types.TBOOL], a, b)
case ir.OMUL: case ir.OMUL:
n := n.(*ir.BinaryExpr)
a := s.expr(n.Left()) a := s.expr(n.Left())
b := s.expr(n.Right()) b := s.expr(n.Right())
if n.Type().IsComplex() { if n.Type().IsComplex() {
@ -2520,6 +2549,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
return s.newValue2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b) return s.newValue2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
case ir.ODIV: case ir.ODIV:
n := n.(*ir.BinaryExpr)
a := s.expr(n.Left()) a := s.expr(n.Left())
b := s.expr(n.Right()) b := s.expr(n.Right())
if n.Type().IsComplex() { if n.Type().IsComplex() {
@ -2567,10 +2597,12 @@ func (s *state) expr(n ir.Node) *ssa.Value {
} }
return s.intDivide(n, a, b) return s.intDivide(n, a, b)
case ir.OMOD: case ir.OMOD:
n := n.(*ir.BinaryExpr)
a := s.expr(n.Left()) a := s.expr(n.Left())
b := s.expr(n.Right()) b := s.expr(n.Right())
return s.intDivide(n, a, b) return s.intDivide(n, a, b)
case ir.OADD, ir.OSUB: case ir.OADD, ir.OSUB:
n := n.(*ir.BinaryExpr)
a := s.expr(n.Left()) a := s.expr(n.Left())
b := s.expr(n.Right()) b := s.expr(n.Right())
if n.Type().IsComplex() { if n.Type().IsComplex() {
@ -2585,15 +2617,18 @@ func (s *state) expr(n ir.Node) *ssa.Value {
} }
return s.newValue2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b) return s.newValue2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
case ir.OAND, ir.OOR, ir.OXOR: case ir.OAND, ir.OOR, ir.OXOR:
n := n.(*ir.BinaryExpr)
a := s.expr(n.Left()) a := s.expr(n.Left())
b := s.expr(n.Right()) b := s.expr(n.Right())
return s.newValue2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b) return s.newValue2(s.ssaOp(n.Op(), n.Type()), a.Type, a, b)
case ir.OANDNOT: case ir.OANDNOT:
n := n.(*ir.BinaryExpr)
a := s.expr(n.Left()) a := s.expr(n.Left())
b := s.expr(n.Right()) b := s.expr(n.Right())
b = s.newValue1(s.ssaOp(ir.OBITNOT, b.Type), b.Type, b) b = s.newValue1(s.ssaOp(ir.OBITNOT, b.Type), b.Type, b)
return s.newValue2(s.ssaOp(ir.OAND, n.Type()), a.Type, a, b) return s.newValue2(s.ssaOp(ir.OAND, n.Type()), a.Type, a, b)
case ir.OLSH, ir.ORSH: case ir.OLSH, ir.ORSH:
n := n.(*ir.BinaryExpr)
a := s.expr(n.Left()) a := s.expr(n.Left())
b := s.expr(n.Right()) b := s.expr(n.Right())
bt := b.Type bt := b.Type
@ -2617,6 +2652,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
// } // }
// Using var in the subsequent block introduces the // Using var in the subsequent block introduces the
// necessary phi variable. // necessary phi variable.
n := n.(*ir.LogicalExpr)
el := s.expr(n.Left()) el := s.expr(n.Left())
s.vars[n] = el s.vars[n] = el
@ -2648,12 +2684,14 @@ func (s *state) expr(n ir.Node) *ssa.Value {
s.startBlock(bResult) s.startBlock(bResult)
return s.variable(n, types.Types[types.TBOOL]) return s.variable(n, types.Types[types.TBOOL])
case ir.OCOMPLEX: case ir.OCOMPLEX:
n := n.(*ir.BinaryExpr)
r := s.expr(n.Left()) r := s.expr(n.Left())
i := s.expr(n.Right()) i := s.expr(n.Right())
return s.newValue2(ssa.OpComplexMake, n.Type(), r, i) return s.newValue2(ssa.OpComplexMake, n.Type(), r, i)
// unary ops // unary ops
case ir.ONEG: case ir.ONEG:
n := n.(*ir.UnaryExpr)
a := s.expr(n.Left()) a := s.expr(n.Left())
if n.Type().IsComplex() { if n.Type().IsComplex() {
tp := floatForComplex(n.Type()) tp := floatForComplex(n.Type())
@ -2664,18 +2702,23 @@ func (s *state) expr(n ir.Node) *ssa.Value {
} }
return s.newValue1(s.ssaOp(n.Op(), n.Type()), a.Type, a) return s.newValue1(s.ssaOp(n.Op(), n.Type()), a.Type, a)
case ir.ONOT, ir.OBITNOT: case ir.ONOT, ir.OBITNOT:
n := n.(*ir.UnaryExpr)
a := s.expr(n.Left()) a := s.expr(n.Left())
return s.newValue1(s.ssaOp(n.Op(), n.Type()), a.Type, a) return s.newValue1(s.ssaOp(n.Op(), n.Type()), a.Type, a)
case ir.OIMAG, ir.OREAL: case ir.OIMAG, ir.OREAL:
n := n.(*ir.UnaryExpr)
a := s.expr(n.Left()) a := s.expr(n.Left())
return s.newValue1(s.ssaOp(n.Op(), n.Left().Type()), n.Type(), a) return s.newValue1(s.ssaOp(n.Op(), n.Left().Type()), n.Type(), a)
case ir.OPLUS: case ir.OPLUS:
n := n.(*ir.UnaryExpr)
return s.expr(n.Left()) return s.expr(n.Left())
case ir.OADDR: case ir.OADDR:
n := n.(*ir.AddrExpr)
return s.addr(n.Left()) return s.addr(n.Left())
case ir.ORESULT: case ir.ORESULT:
n := n.(*ir.ResultExpr)
if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall { if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall {
// Do the old thing // Do the old thing
addr := s.constOffPtrSP(types.NewPtr(n.Type()), n.Offset()) addr := s.constOffPtrSP(types.NewPtr(n.Type()), n.Offset())
@ -2695,6 +2738,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
} }
case ir.ODEREF: case ir.ODEREF:
n := n.(*ir.StarExpr)
p := s.exprPtr(n.Left(), n.Bounded(), n.Pos()) p := s.exprPtr(n.Left(), n.Bounded(), n.Pos())
return s.load(n.Type(), p) return s.load(n.Type(), p)
@ -2721,11 +2765,13 @@ func (s *state) expr(n ir.Node) *ssa.Value {
return s.newValue1I(ssa.OpStructSelect, n.Type(), int64(fieldIdx(n)), v) return s.newValue1I(ssa.OpStructSelect, n.Type(), int64(fieldIdx(n)), v)
case ir.ODOTPTR: case ir.ODOTPTR:
n := n.(*ir.SelectorExpr)
p := s.exprPtr(n.Left(), n.Bounded(), n.Pos()) p := s.exprPtr(n.Left(), n.Bounded(), n.Pos())
p = s.newValue1I(ssa.OpOffPtr, types.NewPtr(n.Type()), n.Offset(), p) p = s.newValue1I(ssa.OpOffPtr, types.NewPtr(n.Type()), n.Offset(), p)
return s.load(n.Type(), p) return s.load(n.Type(), p)
case ir.OINDEX: case ir.OINDEX:
n := n.(*ir.IndexExpr)
switch { switch {
case n.Left().Type().IsString(): case n.Left().Type().IsString():
if n.Bounded() && ir.IsConst(n.Left(), constant.String) && ir.IsConst(n.Right(), constant.Int) { if n.Bounded() && ir.IsConst(n.Left(), constant.String) && ir.IsConst(n.Right(), constant.Int) {
@ -2792,6 +2838,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
} }
case ir.OSPTR: case ir.OSPTR:
n := n.(*ir.UnaryExpr)
a := s.expr(n.Left()) a := s.expr(n.Left())
if n.Left().Type().IsSlice() { if n.Left().Type().IsSlice() {
return s.newValue1(ssa.OpSlicePtr, n.Type(), a) return s.newValue1(ssa.OpSlicePtr, n.Type(), a)
@ -2800,25 +2847,30 @@ func (s *state) expr(n ir.Node) *ssa.Value {
} }
case ir.OITAB: case ir.OITAB:
n := n.(*ir.UnaryExpr)
a := s.expr(n.Left()) a := s.expr(n.Left())
return s.newValue1(ssa.OpITab, n.Type(), a) return s.newValue1(ssa.OpITab, n.Type(), a)
case ir.OIDATA: case ir.OIDATA:
n := n.(*ir.UnaryExpr)
a := s.expr(n.Left()) a := s.expr(n.Left())
return s.newValue1(ssa.OpIData, n.Type(), a) return s.newValue1(ssa.OpIData, n.Type(), a)
case ir.OEFACE: case ir.OEFACE:
n := n.(*ir.BinaryExpr)
tab := s.expr(n.Left()) tab := s.expr(n.Left())
data := s.expr(n.Right()) data := s.expr(n.Right())
return s.newValue2(ssa.OpIMake, n.Type(), tab, data) return s.newValue2(ssa.OpIMake, n.Type(), tab, data)
case ir.OSLICEHEADER: case ir.OSLICEHEADER:
n := n.(*ir.SliceHeaderExpr)
p := s.expr(n.Left()) p := s.expr(n.Left())
l := s.expr(n.List().First()) l := s.expr(n.List().First())
c := s.expr(n.List().Second()) c := s.expr(n.List().Second())
return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c) return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR: case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR:
n := n.(*ir.SliceExpr)
v := s.expr(n.Left()) v := s.expr(n.Left())
var i, j, k *ssa.Value var i, j, k *ssa.Value
low, high, max := n.SliceBounds() low, high, max := n.SliceBounds()
@ -2835,6 +2887,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c) return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
case ir.OSLICESTR: case ir.OSLICESTR:
n := n.(*ir.SliceExpr)
v := s.expr(n.Left()) v := s.expr(n.Left())
var i, j *ssa.Value var i, j *ssa.Value
low, high, _ := n.SliceBounds() low, high, _ := n.SliceBounds()
@ -2859,6 +2912,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
return s.callResult(n, callNormal) return s.callResult(n, callNormal)
case ir.OGETG: case ir.OGETG:
n := n.(*ir.CallExpr)
return s.newValue1(ssa.OpGetG, n.Type(), s.mem()) return s.newValue1(ssa.OpGetG, n.Type(), s.mem())
case ir.OAPPEND: case ir.OAPPEND:
@ -2868,12 +2922,14 @@ func (s *state) expr(n ir.Node) *ssa.Value {
// All literals with nonzero fields have already been // All literals with nonzero fields have already been
// rewritten during walk. Any that remain are just T{} // rewritten during walk. Any that remain are just T{}
// or equivalents. Use the zero value. // or equivalents. Use the zero value.
n := n.(*ir.CompLitExpr)
if !isZero(n) { if !isZero(n) {
s.Fatalf("literal with nonzero value in SSA: %v", n) s.Fatalf("literal with nonzero value in SSA: %v", n)
} }
return s.zeroVal(n.Type()) return s.zeroVal(n.Type())
case ir.ONEWOBJ: case ir.ONEWOBJ:
n := n.(*ir.UnaryExpr)
if n.Type().Elem().Size() == 0 { if n.Type().Elem().Size() == 0 {
return s.newValue1A(ssa.OpAddr, n.Type(), zerobaseSym, s.sb) return s.newValue1A(ssa.OpAddr, n.Type(), zerobaseSym, s.sb)
} }
@ -3057,6 +3113,7 @@ func (s *state) append(n *ir.CallExpr, inplace bool) *ssa.Value {
func (s *state) condBranch(cond ir.Node, yes, no *ssa.Block, likely int8) { func (s *state) condBranch(cond ir.Node, yes, no *ssa.Block, likely int8) {
switch cond.Op() { switch cond.Op() {
case ir.OANDAND: case ir.OANDAND:
cond := cond.(*ir.LogicalExpr)
mid := s.f.NewBlock(ssa.BlockPlain) mid := s.f.NewBlock(ssa.BlockPlain)
s.stmtList(cond.Init()) s.stmtList(cond.Init())
s.condBranch(cond.Left(), mid, no, max8(likely, 0)) s.condBranch(cond.Left(), mid, no, max8(likely, 0))
@ -3070,6 +3127,7 @@ func (s *state) condBranch(cond ir.Node, yes, no *ssa.Block, likely int8) {
// TODO: have the frontend give us branch prediction hints for // TODO: have the frontend give us branch prediction hints for
// OANDAND and OOROR nodes (if it ever has such info). // OANDAND and OOROR nodes (if it ever has such info).
case ir.OOROR: case ir.OOROR:
cond := cond.(*ir.LogicalExpr)
mid := s.f.NewBlock(ssa.BlockPlain) mid := s.f.NewBlock(ssa.BlockPlain)
s.stmtList(cond.Init()) s.stmtList(cond.Init())
s.condBranch(cond.Left(), yes, mid, min8(likely, 0)) s.condBranch(cond.Left(), yes, mid, min8(likely, 0))
@ -3080,10 +3138,12 @@ func (s *state) condBranch(cond ir.Node, yes, no *ssa.Block, likely int8) {
// If likely==1, then we don't have enough info to decide // If likely==1, then we don't have enough info to decide
// the likelihood of the first branch. // the likelihood of the first branch.
case ir.ONOT: case ir.ONOT:
cond := cond.(*ir.UnaryExpr)
s.stmtList(cond.Init()) s.stmtList(cond.Init())
s.condBranch(cond.Left(), no, yes, -likely) s.condBranch(cond.Left(), no, yes, -likely)
return return
case ir.OCONVNOP: case ir.OCONVNOP:
cond := cond.(*ir.ConvExpr)
s.stmtList(cond.Init()) s.stmtList(cond.Init())
s.condBranch(cond.Left(), yes, no, likely) s.condBranch(cond.Left(), yes, no, likely)
return return
@ -3157,6 +3217,7 @@ func (s *state) assign(left ir.Node, right *ssa.Value, deref bool, skip skipMask
return return
} }
if left.Op() == ir.OINDEX && left.(*ir.IndexExpr).Left().Type().IsArray() { if left.Op() == ir.OINDEX && left.(*ir.IndexExpr).Left().Type().IsArray() {
left := left.(*ir.IndexExpr)
s.pushLine(left.Pos()) s.pushLine(left.Pos())
defer s.popLine() defer s.popLine()
// We're assigning to an element of an ssa-able array. // We're assigning to an element of an ssa-able array.
@ -4630,6 +4691,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
case ir.OCALLFUNC: case ir.OCALLFUNC:
testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f) testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
if k == callNormal && fn.Op() == ir.ONAME && fn.(*ir.Name).Class() == ir.PFUNC { if k == callNormal && fn.Op() == ir.ONAME && fn.(*ir.Name).Class() == ir.PFUNC {
fn := fn.(*ir.Name)
sym = fn.Sym() sym = fn.Sym()
break break
} }
@ -5000,6 +5062,7 @@ func (s *state) addr(n ir.Node) *ssa.Value {
} }
case ir.ORESULT: case ir.ORESULT:
// load return from callee // load return from callee
n := n.(*ir.ResultExpr)
if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall { if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall {
return s.constOffPtrSP(t, n.Offset()) return s.constOffPtrSP(t, n.Offset())
} }
@ -5012,6 +5075,7 @@ func (s *state) addr(n ir.Node) *ssa.Value {
return x return x
case ir.OINDEX: case ir.OINDEX:
n := n.(*ir.IndexExpr)
if n.Left().Type().IsSlice() { if n.Left().Type().IsSlice() {
a := s.expr(n.Left()) a := s.expr(n.Left())
i := s.expr(n.Right()) i := s.expr(n.Right())
@ -5027,11 +5091,14 @@ func (s *state) addr(n ir.Node) *ssa.Value {
return s.newValue2(ssa.OpPtrIndex, types.NewPtr(n.Left().Type().Elem()), a, i) return s.newValue2(ssa.OpPtrIndex, types.NewPtr(n.Left().Type().Elem()), a, i)
} }
case ir.ODEREF: case ir.ODEREF:
n := n.(*ir.StarExpr)
return s.exprPtr(n.Left(), n.Bounded(), n.Pos()) return s.exprPtr(n.Left(), n.Bounded(), n.Pos())
case ir.ODOT: case ir.ODOT:
n := n.(*ir.SelectorExpr)
p := s.addr(n.Left()) p := s.addr(n.Left())
return s.newValue1I(ssa.OpOffPtr, t, n.Offset(), p) return s.newValue1I(ssa.OpOffPtr, t, n.Offset(), p)
case ir.ODOTPTR: case ir.ODOTPTR:
n := n.(*ir.SelectorExpr)
p := s.exprPtr(n.Left(), n.Bounded(), n.Pos()) p := s.exprPtr(n.Left(), n.Bounded(), n.Pos())
return s.newValue1I(ssa.OpOffPtr, t, n.Offset(), p) return s.newValue1I(ssa.OpOffPtr, t, n.Offset(), p)
case ir.OCLOSUREREAD: case ir.OCLOSUREREAD:
@ -5039,6 +5106,7 @@ func (s *state) addr(n ir.Node) *ssa.Value {
return s.newValue1I(ssa.OpOffPtr, t, n.Offset(), return s.newValue1I(ssa.OpOffPtr, t, n.Offset(),
s.entryNewValue0(ssa.OpGetClosurePtr, s.f.Config.Types.BytePtr)) s.entryNewValue0(ssa.OpGetClosurePtr, s.f.Config.Types.BytePtr))
case ir.OCONVNOP: case ir.OCONVNOP:
n := n.(*ir.ConvExpr)
if n.Type() == n.Left().Type() { if n.Type() == n.Left().Type() {
return s.addr(n.Left()) return s.addr(n.Left())
} }
@ -5072,10 +5140,12 @@ func (s *state) canSSA(n ir.Node) bool {
for { for {
nn := n nn := n
if nn.Op() == ir.ODOT { if nn.Op() == ir.ODOT {
nn := nn.(*ir.SelectorExpr)
n = nn.Left() n = nn.Left()
continue continue
} }
if nn.Op() == ir.OINDEX { if nn.Op() == ir.OINDEX {
nn := nn.(*ir.IndexExpr)
if nn.Left().Type().IsArray() { if nn.Left().Type().IsArray() {
n = nn.Left() n = nn.Left()
continue continue
@ -7297,11 +7367,13 @@ func (e *ssafn) MyImportPath() string {
func clobberBase(n ir.Node) ir.Node { func clobberBase(n ir.Node) ir.Node {
if n.Op() == ir.ODOT { if n.Op() == ir.ODOT {
n := n.(*ir.SelectorExpr)
if n.Left().Type().NumFields() == 1 { if n.Left().Type().NumFields() == 1 {
return clobberBase(n.Left()) return clobberBase(n.Left())
} }
} }
if n.Op() == ir.OINDEX { if n.Op() == ir.OINDEX {
n := n.(*ir.IndexExpr)
if n.Left().Type().IsArray() && n.Left().Type().NumElem() == 1 { if n.Left().Type().IsArray() && n.Left().Type().NumElem() == 1 {
return clobberBase(n.Left()) return clobberBase(n.Left())
} }

View file

@ -612,6 +612,7 @@ func calcHasCall(n ir.Node) bool {
return true return true
case ir.OANDAND, ir.OOROR: case ir.OANDAND, ir.OOROR:
// hard with instrumented code // hard with instrumented code
n := n.(*ir.LogicalExpr)
if instrumenting { if instrumenting {
return true return true
} }
@ -625,42 +626,52 @@ func calcHasCall(n ir.Node) bool {
// When using soft-float, these ops might be rewritten to function calls // When using soft-float, these ops might be rewritten to function calls
// so we ensure they are evaluated first. // so we ensure they are evaluated first.
case ir.OADD, ir.OSUB, ir.OMUL: case ir.OADD, ir.OSUB, ir.OMUL:
n := n.(*ir.BinaryExpr)
if thearch.SoftFloat && (isFloat[n.Type().Kind()] || isComplex[n.Type().Kind()]) { if thearch.SoftFloat && (isFloat[n.Type().Kind()] || isComplex[n.Type().Kind()]) {
return true return true
} }
return n.Left().HasCall() || n.Right().HasCall() return n.Left().HasCall() || n.Right().HasCall()
case ir.ONEG: case ir.ONEG:
n := n.(*ir.UnaryExpr)
if thearch.SoftFloat && (isFloat[n.Type().Kind()] || isComplex[n.Type().Kind()]) { if thearch.SoftFloat && (isFloat[n.Type().Kind()] || isComplex[n.Type().Kind()]) {
return true return true
} }
return n.Left().HasCall() return n.Left().HasCall()
case ir.OLT, ir.OEQ, ir.ONE, ir.OLE, ir.OGE, ir.OGT: case ir.OLT, ir.OEQ, ir.ONE, ir.OLE, ir.OGE, ir.OGT:
n := n.(*ir.BinaryExpr)
if thearch.SoftFloat && (isFloat[n.Left().Type().Kind()] || isComplex[n.Left().Type().Kind()]) { if thearch.SoftFloat && (isFloat[n.Left().Type().Kind()] || isComplex[n.Left().Type().Kind()]) {
return true return true
} }
return n.Left().HasCall() || n.Right().HasCall() return n.Left().HasCall() || n.Right().HasCall()
case ir.OCONV: case ir.OCONV:
n := n.(*ir.ConvExpr)
if thearch.SoftFloat && ((isFloat[n.Type().Kind()] || isComplex[n.Type().Kind()]) || (isFloat[n.Left().Type().Kind()] || isComplex[n.Left().Type().Kind()])) { if thearch.SoftFloat && ((isFloat[n.Type().Kind()] || isComplex[n.Type().Kind()]) || (isFloat[n.Left().Type().Kind()] || isComplex[n.Left().Type().Kind()])) {
return true return true
} }
return n.Left().HasCall() return n.Left().HasCall()
case ir.OAND, ir.OANDNOT, ir.OLSH, ir.OOR, ir.ORSH, ir.OXOR, ir.OCOPY, ir.OCOMPLEX, ir.OEFACE: case ir.OAND, ir.OANDNOT, ir.OLSH, ir.OOR, ir.ORSH, ir.OXOR, ir.OCOPY, ir.OCOMPLEX, ir.OEFACE:
n := n.(*ir.BinaryExpr)
return n.Left().HasCall() || n.Right().HasCall() return n.Left().HasCall() || n.Right().HasCall()
case ir.OAS: case ir.OAS:
n := n.(*ir.AssignStmt)
return n.Left().HasCall() || n.Right() != nil && n.Right().HasCall() return n.Left().HasCall() || n.Right() != nil && n.Right().HasCall()
case ir.OADDR: case ir.OADDR:
n := n.(*ir.AddrExpr)
return n.Left().HasCall() return n.Left().HasCall()
case ir.OPAREN: case ir.OPAREN:
n := n.(*ir.ParenExpr)
return n.Left().HasCall() return n.Left().HasCall()
case ir.OBITNOT, ir.ONOT, ir.OPLUS, ir.ORECV, case ir.OBITNOT, ir.ONOT, ir.OPLUS, ir.ORECV,
ir.OALIGNOF, ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.ONEW, ir.OALIGNOF, ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.ONEW,
ir.OOFFSETOF, ir.OPANIC, ir.OREAL, ir.OSIZEOF, ir.OOFFSETOF, ir.OPANIC, ir.OREAL, ir.OSIZEOF,
ir.OCHECKNIL, ir.OCFUNC, ir.OIDATA, ir.OITAB, ir.ONEWOBJ, ir.OSPTR, ir.OVARDEF, ir.OVARKILL, ir.OVARLIVE: ir.OCHECKNIL, ir.OCFUNC, ir.OIDATA, ir.OITAB, ir.ONEWOBJ, ir.OSPTR, ir.OVARDEF, ir.OVARKILL, ir.OVARLIVE:
n := n.(*ir.UnaryExpr)
return n.Left().HasCall() return n.Left().HasCall()
case ir.ODOT, ir.ODOTMETH, ir.ODOTINTER: case ir.ODOT, ir.ODOTMETH, ir.ODOTINTER:
n := n.(*ir.SelectorExpr)
return n.Left().HasCall() return n.Left().HasCall()
case ir.OGETG, ir.OCLOSUREREAD, ir.OMETHEXPR: case ir.OGETG, ir.OCLOSUREREAD, ir.OMETHEXPR:
@ -675,12 +686,15 @@ func calcHasCall(n ir.Node) bool {
return false return false
case ir.OCONVIFACE, ir.OCONVNOP, ir.OBYTES2STR, ir.OBYTES2STRTMP, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2BYTESTMP, ir.OSTR2RUNES, ir.ORUNESTR: case ir.OCONVIFACE, ir.OCONVNOP, ir.OBYTES2STR, ir.OBYTES2STRTMP, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2BYTESTMP, ir.OSTR2RUNES, ir.ORUNESTR:
// TODO(rsc): Some conversions are themselves calls, no? // TODO(rsc): Some conversions are themselves calls, no?
n := n.(*ir.ConvExpr)
return n.Left().HasCall() return n.Left().HasCall()
case ir.ODOTTYPE2: case ir.ODOTTYPE2:
// TODO(rsc): Shouldn't this be up with ODOTTYPE above? // TODO(rsc): Shouldn't this be up with ODOTTYPE above?
n := n.(*ir.TypeAssertExpr)
return n.Left().HasCall() return n.Left().HasCall()
case ir.OSLICEHEADER: case ir.OSLICEHEADER:
// TODO(rsc): What about len and cap? // TODO(rsc): What about len and cap?
n := n.(*ir.SliceHeaderExpr)
return n.Left().HasCall() return n.Left().HasCall()
case ir.OAS2DOTTYPE, ir.OAS2FUNC: case ir.OAS2DOTTYPE, ir.OAS2FUNC:
// TODO(rsc): Surely we need to check List and Rlist. // TODO(rsc): Surely we need to check List and Rlist.
@ -768,6 +782,7 @@ func safeexpr(n ir.Node, init *ir.Nodes) ir.Node {
return n return n
case ir.OLEN, ir.OCAP: case ir.OLEN, ir.OCAP:
n := n.(*ir.UnaryExpr)
l := safeexpr(n.Left(), init) l := safeexpr(n.Left(), init)
if l == n.Left() { if l == n.Left() {
return n return n
@ -777,6 +792,7 @@ func safeexpr(n ir.Node, init *ir.Nodes) ir.Node {
return walkexpr(typecheck(a, ctxExpr), init) return walkexpr(typecheck(a, ctxExpr), init)
case ir.ODOT, ir.ODOTPTR: case ir.ODOT, ir.ODOTPTR:
n := n.(*ir.SelectorExpr)
l := safeexpr(n.Left(), init) l := safeexpr(n.Left(), init)
if l == n.Left() { if l == n.Left() {
return n return n
@ -786,6 +802,7 @@ func safeexpr(n ir.Node, init *ir.Nodes) ir.Node {
return walkexpr(typecheck(a, ctxExpr), init) return walkexpr(typecheck(a, ctxExpr), init)
case ir.ODEREF: case ir.ODEREF:
n := n.(*ir.StarExpr)
l := safeexpr(n.Left(), init) l := safeexpr(n.Left(), init)
if l == n.Left() { if l == n.Left() {
return n return n
@ -795,6 +812,7 @@ func safeexpr(n ir.Node, init *ir.Nodes) ir.Node {
return walkexpr(typecheck(a, ctxExpr), init) return walkexpr(typecheck(a, ctxExpr), init)
case ir.OINDEX, ir.OINDEXMAP: case ir.OINDEX, ir.OINDEXMAP:
n := n.(*ir.IndexExpr)
l := safeexpr(n.Left(), init) l := safeexpr(n.Left(), init)
r := safeexpr(n.Right(), init) r := safeexpr(n.Right(), init)
if l == n.Left() && r == n.Right() { if l == n.Left() && r == n.Right() {
@ -806,6 +824,7 @@ func safeexpr(n ir.Node, init *ir.Nodes) ir.Node {
return walkexpr(typecheck(a, ctxExpr), init) return walkexpr(typecheck(a, ctxExpr), init)
case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT: case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT:
n := n.(*ir.CompLitExpr)
if isStaticCompositeLiteral(n) { if isStaticCompositeLiteral(n) {
return n return n
} }

View file

@ -266,6 +266,7 @@ func walkExprSwitch(sw *ir.SwitchStmt) {
// conversion into a runtime call. // conversion into a runtime call.
// See issue 24937 for more discussion. // See issue 24937 for more discussion.
if cond.Op() == ir.OBYTES2STR && allCaseExprsAreSideEffectFree(sw) { if cond.Op() == ir.OBYTES2STR && allCaseExprsAreSideEffectFree(sw) {
cond := cond.(*ir.ConvExpr)
cond.SetOp(ir.OBYTES2STRTMP) cond.SetOp(ir.OBYTES2STRTMP)
} }

View file

@ -412,6 +412,7 @@ func typecheck(n ir.Node, top int) (res ir.Node) {
switch n.Op() { switch n.Op() {
// We can already diagnose variables used as types. // We can already diagnose variables used as types.
case ir.ONAME: case ir.ONAME:
n := n.(*ir.Name)
if top&(ctxExpr|ctxType) == ctxType { if top&(ctxExpr|ctxType) == ctxType {
base.Errorf("%v is not a type", n) base.Errorf("%v is not a type", n)
} }
@ -477,6 +478,7 @@ func typecheck(n ir.Node, top int) (res ir.Node) {
isMulti := false isMulti := false
switch n.Op() { switch n.Op() {
case ir.OCALLFUNC, ir.OCALLINTER, ir.OCALLMETH: case ir.OCALLFUNC, ir.OCALLINTER, ir.OCALLMETH:
n := n.(*ir.CallExpr)
if t := n.Left().Type(); t != nil && t.Kind() == types.TFUNC { if t := n.Left().Type(); t != nil && t.Kind() == types.TFUNC {
nr := t.NumResults() nr := t.NumResults()
isMulti = nr > 1 isMulti = nr > 1
@ -577,6 +579,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
if n.Op() == ir.ONAME { if n.Op() == ir.ONAME {
n := n.(*ir.Name)
if n.SubOp() != 0 && top&ctxCallee == 0 { if n.SubOp() != 0 && top&ctxCallee == 0 {
base.Errorf("use of builtin %v not in function call", n.Sym()) base.Errorf("use of builtin %v not in function call", n.Sym())
n.SetType(nil) n.SetType(nil)
@ -608,6 +611,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.ONAME: case ir.ONAME:
n := n.(*ir.Name)
if n.Name().Decldepth == 0 { if n.Name().Decldepth == 0 {
n.Name().Decldepth = decldepth n.Name().Decldepth = decldepth
} }
@ -630,6 +634,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OPACK: case ir.OPACK:
n := n.(*ir.PkgName)
base.Errorf("use of package %v without selector", n.Sym()) base.Errorf("use of package %v without selector", n.Sym())
n.SetType(nil) n.SetType(nil)
return n return n
@ -816,6 +821,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
op := n.Op() op := n.Op()
if n.Op() == ir.OASOP { if n.Op() == ir.OASOP {
n := n.(*ir.AssignOpStmt)
checkassign(n, l) checkassign(n, l)
if n.Implicit() && !okforarith[l.Type().Kind()] { if n.Implicit() && !okforarith[l.Type().Kind()] {
base.Errorf("invalid operation: %v (non-numeric type %v)", n, l.Type()) base.Errorf("invalid operation: %v (non-numeric type %v)", n, l.Type())
@ -859,6 +865,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
// can't be used with "&&" than to report that "x == x" (type untyped bool) // can't be used with "&&" than to report that "x == x" (type untyped bool)
// can't be converted to int (see issue #41500). // can't be converted to int (see issue #41500).
if n.Op() == ir.OANDAND || n.Op() == ir.OOROR { if n.Op() == ir.OANDAND || n.Op() == ir.OOROR {
n := n.(*ir.LogicalExpr)
if !n.Left().Type().IsBoolean() { if !n.Left().Type().IsBoolean() {
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(n.Left().Type())) base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(n.Left().Type()))
n.SetType(nil) n.SetType(nil)
@ -1010,6 +1017,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
if et == types.TSTRING && n.Op() == ir.OADD { if et == types.TSTRING && n.Op() == ir.OADD {
// create or update OADDSTR node with list of strings in x + y + z + (w + v) + ... // create or update OADDSTR node with list of strings in x + y + z + (w + v) + ...
n := n.(*ir.BinaryExpr)
var add *ir.AddStringExpr var add *ir.AddStringExpr
if l.Op() == ir.OADDSTR { if l.Op() == ir.OADDSTR {
add = l.(*ir.AddStringExpr) add = l.(*ir.AddStringExpr)
@ -1018,6 +1026,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
add = ir.NewAddStringExpr(n.Pos(), []ir.Node{l}) add = ir.NewAddStringExpr(n.Pos(), []ir.Node{l})
} }
if r.Op() == ir.OADDSTR { if r.Op() == ir.OADDSTR {
r := r.(*ir.AddStringExpr)
add.PtrList().AppendNodes(r.PtrList()) add.PtrList().AppendNodes(r.PtrList())
} else { } else {
add.PtrList().Append(r) add.PtrList().Append(r)
@ -1038,6 +1047,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OBITNOT, ir.ONEG, ir.ONOT, ir.OPLUS: case ir.OBITNOT, ir.ONEG, ir.ONOT, ir.OPLUS:
n := n.(*ir.UnaryExpr)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
l := n.Left() l := n.Left()
t := l.Type() t := l.Type()
@ -1056,6 +1066,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
// exprs // exprs
case ir.OADDR: case ir.OADDR:
n := n.(*ir.AddrExpr)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
if n.Left().Type() == nil { if n.Left().Type() == nil {
n.SetType(nil) n.SetType(nil)
@ -1070,6 +1081,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
checklvalue(n.Left(), "take the address of") checklvalue(n.Left(), "take the address of")
r := outervalue(n.Left()) r := outervalue(n.Left())
if r.Op() == ir.ONAME { if r.Op() == ir.ONAME {
r := r.(*ir.Name)
if ir.Orig(r) != r { if ir.Orig(r) != r {
base.Fatalf("found non-orig name node %v", r) // TODO(mdempsky): What does this mean? base.Fatalf("found non-orig name node %v", r) // TODO(mdempsky): What does this mean?
} }
@ -1170,6 +1182,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.ODOTTYPE: case ir.ODOTTYPE:
n := n.(*ir.TypeAssertExpr)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
l := n.Left() l := n.Left()
@ -1215,6 +1228,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OINDEX: case ir.OINDEX:
n := n.(*ir.IndexExpr)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
n.SetLeft(implicitstar(n.Left())) n.SetLeft(implicitstar(n.Left()))
@ -1273,6 +1287,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.ORECV: case ir.ORECV:
n := n.(*ir.UnaryExpr)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
l := n.Left() l := n.Left()
@ -1297,6 +1312,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OSEND: case ir.OSEND:
n := n.(*ir.SendStmt)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetRight(typecheck(n.Right(), ctxExpr)) n.SetRight(typecheck(n.Right(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
@ -1325,6 +1341,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
// can construct an OSLICEHEADER node. // can construct an OSLICEHEADER node.
// Components used in OSLICEHEADER that are supplied by parsed source code // Components used in OSLICEHEADER that are supplied by parsed source code
// have already been typechecked in e.g. OMAKESLICE earlier. // have already been typechecked in e.g. OMAKESLICE earlier.
n := n.(*ir.SliceHeaderExpr)
t := n.Type() t := n.Type()
if t == nil { if t == nil {
base.Fatalf("no type specified for OSLICEHEADER") base.Fatalf("no type specified for OSLICEHEADER")
@ -1369,6 +1386,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
// can construct an OMAKESLICECOPY node. // can construct an OMAKESLICECOPY node.
// Components used in OMAKESCLICECOPY that are supplied by parsed source code // Components used in OMAKESCLICECOPY that are supplied by parsed source code
// have already been typechecked in OMAKE and OCOPY earlier. // have already been typechecked in OMAKE and OCOPY earlier.
n := n.(*ir.MakeExpr)
t := n.Type() t := n.Type()
if t == nil { if t == nil {
@ -1407,6 +1425,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OSLICE, ir.OSLICE3: case ir.OSLICE, ir.OSLICE3:
n := n.(*ir.SliceExpr)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
low, high, max := n.SliceBounds() low, high, max := n.SliceBounds()
hasmax := n.Op().IsSlice3() hasmax := n.Op().IsSlice3()
@ -1496,6 +1515,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
l := n.Left() l := n.Left()
if l.Op() == ir.ONAME && l.(*ir.Name).SubOp() != 0 { if l.Op() == ir.ONAME && l.(*ir.Name).SubOp() != 0 {
l := l.(*ir.Name)
if n.IsDDD() && l.SubOp() != ir.OAPPEND { if n.IsDDD() && l.SubOp() != ir.OAPPEND {
base.Errorf("invalid use of ... with builtin %v", l) base.Errorf("invalid use of ... with builtin %v", l)
} }
@ -1571,6 +1591,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
n.SetOp(ir.OCALLINTER) n.SetOp(ir.OCALLINTER)
case ir.ODOTMETH: case ir.ODOTMETH:
l := l.(*ir.SelectorExpr)
n.SetOp(ir.OCALLMETH) n.SetOp(ir.OCALLMETH)
// typecheckaste was used here but there wasn't enough // typecheckaste was used here but there wasn't enough
@ -1632,10 +1653,12 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF: case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
n := n.(*ir.UnaryExpr)
n.SetType(types.Types[types.TUINTPTR]) n.SetType(types.Types[types.TUINTPTR])
return n return n
case ir.OCAP, ir.OLEN: case ir.OCAP, ir.OLEN:
n := n.(*ir.UnaryExpr)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
n.SetLeft(implicitstar(n.Left())) n.SetLeft(implicitstar(n.Left()))
@ -1662,6 +1685,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OREAL, ir.OIMAG: case ir.OREAL, ir.OIMAG:
n := n.(*ir.UnaryExpr)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
l := n.Left() l := n.Left()
t := l.Type() t := l.Type()
@ -1686,6 +1710,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OCOMPLEX: case ir.OCOMPLEX:
n := n.(*ir.BinaryExpr)
l := typecheck(n.Left(), ctxExpr) l := typecheck(n.Left(), ctxExpr)
r := typecheck(n.Right(), ctxExpr) r := typecheck(n.Right(), ctxExpr)
if l.Type() == nil || r.Type() == nil { if l.Type() == nil || r.Type() == nil {
@ -1726,6 +1751,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OCLOSE: case ir.OCLOSE:
n := n.(*ir.UnaryExpr)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
l := n.Left() l := n.Left()
@ -1748,6 +1774,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.ODELETE: case ir.ODELETE:
n := n.(*ir.CallExpr)
typecheckargs(n) typecheckargs(n)
args := n.List() args := n.List()
if args.Len() == 0 { if args.Len() == 0 {
@ -1780,6 +1807,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OAPPEND: case ir.OAPPEND:
n := n.(*ir.CallExpr)
typecheckargs(n) typecheckargs(n)
args := n.List() args := n.List()
if args.Len() == 0 { if args.Len() == 0 {
@ -1840,6 +1868,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OCOPY: case ir.OCOPY:
n := n.(*ir.BinaryExpr)
n.SetType(types.Types[types.TINT]) n.SetType(types.Types[types.TINT])
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
@ -1925,6 +1954,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OMAKE: case ir.OMAKE:
n := n.(*ir.CallExpr)
args := n.List().Slice() args := n.List().Slice()
if len(args) == 0 { if len(args) == 0 {
base.Errorf("missing argument to make") base.Errorf("missing argument to make")
@ -2032,6 +2062,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return nn return nn
case ir.ONEW: case ir.ONEW:
n := n.(*ir.UnaryExpr)
if n.Left() == nil { if n.Left() == nil {
// Fatalf because the OCALL above checked for us, // Fatalf because the OCALL above checked for us,
// so this must be an internally-generated mistake. // so this must be an internally-generated mistake.
@ -2049,6 +2080,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OPRINT, ir.OPRINTN: case ir.OPRINT, ir.OPRINTN:
n := n.(*ir.CallExpr)
typecheckargs(n) typecheckargs(n)
ls := n.List().Slice() ls := n.List().Slice()
for i1, n1 := range ls { for i1, n1 := range ls {
@ -2062,6 +2094,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OPANIC: case ir.OPANIC:
n := n.(*ir.UnaryExpr)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), types.Types[types.TINTER])) n.SetLeft(defaultlit(n.Left(), types.Types[types.TINTER]))
if n.Left().Type() == nil { if n.Left().Type() == nil {
@ -2071,6 +2104,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.ORECOVER: case ir.ORECOVER:
n := n.(*ir.CallExpr)
if n.List().Len() != 0 { if n.List().Len() != 0 {
base.Errorf("too many arguments to recover") base.Errorf("too many arguments to recover")
n.SetType(nil) n.SetType(nil)
@ -2089,6 +2123,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OITAB: case ir.OITAB:
n := n.(*ir.UnaryExpr)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
t := n.Left().Type() t := n.Left().Type()
if t == nil { if t == nil {
@ -2104,10 +2139,12 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
case ir.OIDATA: case ir.OIDATA:
// Whoever creates the OIDATA node must know a priori the concrete type at that moment, // Whoever creates the OIDATA node must know a priori the concrete type at that moment,
// usually by just having checked the OITAB. // usually by just having checked the OITAB.
n := n.(*ir.UnaryExpr)
base.Fatalf("cannot typecheck interface data %v", n) base.Fatalf("cannot typecheck interface data %v", n)
panic("unreachable") panic("unreachable")
case ir.OSPTR: case ir.OSPTR:
n := n.(*ir.UnaryExpr)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
t := n.Left().Type() t := n.Left().Type()
if t == nil { if t == nil {
@ -2128,11 +2165,13 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OCFUNC: case ir.OCFUNC:
n := n.(*ir.UnaryExpr)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetType(types.Types[types.TUINTPTR]) n.SetType(types.Types[types.TUINTPTR])
return n return n
case ir.OCONVNOP: case ir.OCONVNOP:
n := n.(*ir.ConvExpr)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
return n return n
@ -2161,6 +2200,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OBLOCK: case ir.OBLOCK:
n := n.(*ir.BlockStmt)
typecheckslice(n.List().Slice(), ctxStmt) typecheckslice(n.List().Slice(), ctxStmt)
return n return n
@ -2183,6 +2223,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OFOR, ir.OFORUNTIL: case ir.OFOR, ir.OFORUNTIL:
n := n.(*ir.ForStmt)
typecheckslice(n.Init().Slice(), ctxStmt) typecheckslice(n.Init().Slice(), ctxStmt)
decldepth++ decldepth++
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
@ -2202,6 +2243,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OIF: case ir.OIF:
n := n.(*ir.IfStmt)
typecheckslice(n.Init().Slice(), ctxStmt) typecheckslice(n.Init().Slice(), ctxStmt)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
@ -2216,6 +2258,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.ORETURN: case ir.ORETURN:
n := n.(*ir.ReturnStmt)
typecheckargs(n) typecheckargs(n)
if Curfn == nil { if Curfn == nil {
base.Errorf("return outside function") base.Errorf("return outside function")
@ -2230,6 +2273,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.ORETJMP: case ir.ORETJMP:
n := n.(*ir.BranchStmt)
return n return n
case ir.OSELECT: case ir.OSELECT:
@ -2245,6 +2289,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.OTYPESW: case ir.OTYPESW:
n := n.(*ir.TypeSwitchGuard)
base.Errorf("use of .(type) outside type switch") base.Errorf("use of .(type) outside type switch")
n.SetType(nil) n.SetType(nil)
return n return n
@ -2254,10 +2299,12 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.ODCLCONST: case ir.ODCLCONST:
n := n.(*ir.Decl)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
return n return n
case ir.ODCLTYPE: case ir.ODCLTYPE:
n := n.(*ir.Decl)
n.SetLeft(typecheck(n.Left(), ctxType)) n.SetLeft(typecheck(n.Left(), ctxType))
checkwidth(n.Left().Type()) checkwidth(n.Left().Type())
return n return n
@ -2814,6 +2861,7 @@ notenough:
// Method expressions have the form T.M, and the compiler has // Method expressions have the form T.M, and the compiler has
// rewritten those to ONAME nodes but left T in Left. // rewritten those to ONAME nodes but left T in Left.
if call.Op() == ir.OMETHEXPR { if call.Op() == ir.OMETHEXPR {
call := call.(*ir.MethodExpr)
base.Errorf("not enough arguments in call to method expression %v%s", call, details) base.Errorf("not enough arguments in call to method expression %v%s", call, details)
} else { } else {
base.Errorf("not enough arguments in call to %v%s", call, details) base.Errorf("not enough arguments in call to %v%s", call, details)
@ -3231,6 +3279,7 @@ func nonexported(sym *types.Sym) bool {
func islvalue(n ir.Node) bool { func islvalue(n ir.Node) bool {
switch n.Op() { switch n.Op() {
case ir.OINDEX: case ir.OINDEX:
n := n.(*ir.IndexExpr)
if n.Left().Type() != nil && n.Left().Type().IsArray() { if n.Left().Type() != nil && n.Left().Type().IsArray() {
return islvalue(n.Left()) return islvalue(n.Left())
} }
@ -3242,9 +3291,11 @@ func islvalue(n ir.Node) bool {
return true return true
case ir.ODOT: case ir.ODOT:
n := n.(*ir.SelectorExpr)
return islvalue(n.Left()) return islvalue(n.Left())
case ir.ONAME: case ir.ONAME:
n := n.(*ir.Name)
if n.Class() == ir.PFUNC { if n.Class() == ir.PFUNC {
return false return false
} }
@ -3268,6 +3319,7 @@ func checkassign(stmt ir.Node, n ir.Node) {
if !ir.DeclaredBy(n, stmt) || stmt.Op() == ir.ORANGE { if !ir.DeclaredBy(n, stmt) || stmt.Op() == ir.ORANGE {
r := outervalue(n) r := outervalue(n)
if r.Op() == ir.ONAME { if r.Op() == ir.ONAME {
r := r.(*ir.Name)
r.Name().SetAssigned(true) r.Name().SetAssigned(true)
if r.Name().IsClosureVar() { if r.Name().IsClosureVar() {
r.Name().Defn.Name().SetAssigned(true) r.Name().Defn.Name().SetAssigned(true)
@ -3279,6 +3331,7 @@ func checkassign(stmt ir.Node, n ir.Node) {
return return
} }
if n.Op() == ir.OINDEXMAP { if n.Op() == ir.OINDEXMAP {
n := n.(*ir.IndexExpr)
n.SetIndexMapLValue(true) n.SetIndexMapLValue(true)
return return
} }
@ -3529,6 +3582,7 @@ func typecheckas2(n *ir.AssignListStmt) {
case ir.ORECV: case ir.ORECV:
n.SetOp(ir.OAS2RECV) n.SetOp(ir.OAS2RECV)
case ir.ODOTTYPE: case ir.ODOTTYPE:
r := r.(*ir.TypeAssertExpr)
n.SetOp(ir.OAS2DOTTYPE) n.SetOp(ir.OAS2DOTTYPE)
r.SetOp(ir.ODOTTYPE2) r.SetOp(ir.ODOTTYPE2)
} }
@ -3554,6 +3608,7 @@ mismatch:
default: default:
base.Errorf("assignment mismatch: %d variables but %d values", cl, cr) base.Errorf("assignment mismatch: %d variables but %d values", cl, cr)
case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER: case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
r := r.(*ir.CallExpr)
base.Errorf("assignment mismatch: %d variables but %v returns %d values", cl, r.Left(), cr) base.Errorf("assignment mismatch: %d variables but %v returns %d values", cl, r.Left(), cr)
} }
@ -3768,6 +3823,7 @@ func typecheckdef(n ir.Node) {
} }
case ir.ONAME: case ir.ONAME:
n := n.(*ir.Name)
if n.Name().Ntype != nil { if n.Name().Ntype != nil {
n.Name().Ntype = typecheckNtype(n.Name().Ntype) n.Name().Ntype = typecheckNtype(n.Name().Ntype)
n.SetType(n.Name().Ntype.Type()) n.SetType(n.Name().Ntype.Type())
@ -3888,6 +3944,7 @@ func markBreak(fn *ir.Func) {
ir.DoChildren(n, mark) ir.DoChildren(n, mark)
case ir.OBREAK: case ir.OBREAK:
n := n.(*ir.BranchStmt)
if n.Sym() == nil { if n.Sym() == nil {
setHasBreak(implicit) setHasBreak(implicit)
} else { } else {
@ -3980,12 +4037,14 @@ func isTermNode(n ir.Node) bool {
// skipping over the label. No case OLABEL here. // skipping over the label. No case OLABEL here.
case ir.OBLOCK: case ir.OBLOCK:
n := n.(*ir.BlockStmt)
return isTermNodes(n.List()) return isTermNodes(n.List())
case ir.OGOTO, ir.ORETURN, ir.ORETJMP, ir.OPANIC, ir.OFALL: case ir.OGOTO, ir.ORETURN, ir.ORETJMP, ir.OPANIC, ir.OFALL:
return true return true
case ir.OFOR, ir.OFORUNTIL: case ir.OFOR, ir.OFORUNTIL:
n := n.(*ir.ForStmt)
if n.Left() != nil { if n.Left() != nil {
return false return false
} }
@ -3995,9 +4054,11 @@ func isTermNode(n ir.Node) bool {
return true return true
case ir.OIF: case ir.OIF:
n := n.(*ir.IfStmt)
return isTermNodes(n.Body()) && isTermNodes(n.Rlist()) return isTermNodes(n.Body()) && isTermNodes(n.Rlist())
case ir.OSWITCH: case ir.OSWITCH:
n := n.(*ir.SwitchStmt)
if n.HasBreak() { if n.HasBreak() {
return false return false
} }
@ -4014,6 +4075,7 @@ func isTermNode(n ir.Node) bool {
return def return def
case ir.OSELECT: case ir.OSELECT:
n := n.(*ir.SelectStmt)
if n.HasBreak() { if n.HasBreak() {
return false return false
} }
@ -4052,10 +4114,12 @@ func deadcode(fn *ir.Func) {
} }
switch n.Op() { switch n.Op() {
case ir.OIF: case ir.OIF:
n := n.(*ir.IfStmt)
if !ir.IsConst(n.Left(), constant.Bool) || n.Body().Len() > 0 || n.Rlist().Len() > 0 { if !ir.IsConst(n.Left(), constant.Bool) || n.Body().Len() > 0 || n.Rlist().Len() > 0 {
return return
} }
case ir.OFOR: case ir.OFOR:
n := n.(*ir.ForStmt)
if !ir.IsConst(n.Left(), constant.Bool) || ir.BoolVal(n.Left()) { if !ir.IsConst(n.Left(), constant.Bool) || ir.BoolVal(n.Left()) {
return return
} }
@ -4083,6 +4147,7 @@ func deadcodeslice(nn *ir.Nodes) {
continue continue
} }
if n.Op() == ir.OIF { if n.Op() == ir.OIF {
n := n.(*ir.IfStmt)
n.SetLeft(deadcodeexpr(n.Left())) n.SetLeft(deadcodeexpr(n.Left()))
if ir.IsConst(n.Left(), constant.Bool) { if ir.IsConst(n.Left(), constant.Bool) {
var body ir.Nodes var body ir.Nodes
@ -4112,19 +4177,26 @@ func deadcodeslice(nn *ir.Nodes) {
deadcodeslice(n.PtrInit()) deadcodeslice(n.PtrInit())
switch n.Op() { switch n.Op() {
case ir.OBLOCK: case ir.OBLOCK:
n := n.(*ir.BlockStmt)
deadcodeslice(n.PtrList()) deadcodeslice(n.PtrList())
case ir.OCASE: case ir.OCASE:
n := n.(*ir.CaseStmt)
deadcodeslice(n.PtrBody()) deadcodeslice(n.PtrBody())
case ir.OFOR: case ir.OFOR:
n := n.(*ir.ForStmt)
deadcodeslice(n.PtrBody()) deadcodeslice(n.PtrBody())
case ir.OIF: case ir.OIF:
n := n.(*ir.IfStmt)
deadcodeslice(n.PtrBody()) deadcodeslice(n.PtrBody())
deadcodeslice(n.PtrRlist()) deadcodeslice(n.PtrRlist())
case ir.ORANGE: case ir.ORANGE:
n := n.(*ir.RangeStmt)
deadcodeslice(n.PtrBody()) deadcodeslice(n.PtrBody())
case ir.OSELECT: case ir.OSELECT:
n := n.(*ir.SelectStmt)
deadcodeslice(n.PtrList()) deadcodeslice(n.PtrList())
case ir.OSWITCH: case ir.OSWITCH:
n := n.(*ir.SwitchStmt)
deadcodeslice(n.PtrList()) deadcodeslice(n.PtrList())
} }
@ -4141,6 +4213,7 @@ func deadcodeexpr(n ir.Node) ir.Node {
// producing a constant 'if' condition. // producing a constant 'if' condition.
switch n.Op() { switch n.Op() {
case ir.OANDAND: case ir.OANDAND:
n := n.(*ir.LogicalExpr)
n.SetLeft(deadcodeexpr(n.Left())) n.SetLeft(deadcodeexpr(n.Left()))
n.SetRight(deadcodeexpr(n.Right())) n.SetRight(deadcodeexpr(n.Right()))
if ir.IsConst(n.Left(), constant.Bool) { if ir.IsConst(n.Left(), constant.Bool) {
@ -4151,6 +4224,7 @@ func deadcodeexpr(n ir.Node) ir.Node {
} }
} }
case ir.OOROR: case ir.OOROR:
n := n.(*ir.LogicalExpr)
n.SetLeft(deadcodeexpr(n.Left())) n.SetLeft(deadcodeexpr(n.Left()))
n.SetRight(deadcodeexpr(n.Right())) n.SetRight(deadcodeexpr(n.Right()))
if ir.IsConst(n.Left(), constant.Bool) { if ir.IsConst(n.Left(), constant.Bool) {
@ -4206,6 +4280,7 @@ func methodExprFunc(n ir.Node) *types.Field {
case ir.OMETHEXPR: case ir.OMETHEXPR:
return n.(*ir.MethodExpr).Method return n.(*ir.MethodExpr).Method
case ir.OCALLPART: case ir.OCALLPART:
n := n.(*ir.CallPartExpr)
return callpartMethod(n) return callpartMethod(n)
} }
base.Fatalf("unexpected node: %v (%v)", n, n.Op()) base.Fatalf("unexpected node: %v (%v)", n, n.Op())

View file

@ -13,6 +13,7 @@ import (
func evalunsafe(n ir.Node) int64 { func evalunsafe(n ir.Node) int64 {
switch n.Op() { switch n.Op() {
case ir.OALIGNOF, ir.OSIZEOF: case ir.OALIGNOF, ir.OSIZEOF:
n := n.(*ir.UnaryExpr)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
tr := n.Left().Type() tr := n.Left().Type()
@ -27,6 +28,7 @@ func evalunsafe(n ir.Node) int64 {
case ir.OOFFSETOF: case ir.OOFFSETOF:
// must be a selector. // must be a selector.
n := n.(*ir.UnaryExpr)
if n.Left().Op() != ir.OXDOT { if n.Left().Op() != ir.OXDOT {
base.Errorf("invalid expression %v", n) base.Errorf("invalid expression %v", n)
return 0 return 0
@ -64,12 +66,14 @@ func evalunsafe(n ir.Node) int64 {
// For Offsetof(s.f), s may itself be a pointer, // For Offsetof(s.f), s may itself be a pointer,
// but accessing f must not otherwise involve // but accessing f must not otherwise involve
// indirection via embedded pointer types. // indirection via embedded pointer types.
r := r.(*ir.SelectorExpr)
if r.Left() != sbase { if r.Left() != sbase {
base.Errorf("invalid expression %v: selector implies indirection of embedded %v", n, r.Left()) base.Errorf("invalid expression %v: selector implies indirection of embedded %v", n, r.Left())
return 0 return 0
} }
fallthrough fallthrough
case ir.ODOT: case ir.ODOT:
r := r.(*ir.SelectorExpr)
v += r.Offset() v += r.Offset()
next = r.Left() next = r.Left()
default: default:

View file

@ -127,6 +127,7 @@ func walkstmt(n ir.Node) ir.Node {
switch n.Op() { switch n.Op() {
default: default:
if n.Op() == ir.ONAME { if n.Op() == ir.ONAME {
n := n.(*ir.Name)
base.Errorf("%v is not a top level statement", n.Sym()) base.Errorf("%v is not a top level statement", n.Sym())
} else { } else {
base.Errorf("%v is not a top level statement", n.Op()) base.Errorf("%v is not a top level statement", n.Op())
@ -181,6 +182,7 @@ func walkstmt(n ir.Node) ir.Node {
// special case for a receive where we throw away // special case for a receive where we throw away
// the value received. // the value received.
case ir.ORECV: case ir.ORECV:
n := n.(*ir.UnaryExpr)
if n.Typecheck() == 0 { if n.Typecheck() == 0 {
base.Fatalf("missing typecheck: %+v", n) base.Fatalf("missing typecheck: %+v", n)
} }
@ -205,6 +207,7 @@ func walkstmt(n ir.Node) ir.Node {
return n return n
case ir.ODCL: case ir.ODCL:
n := n.(*ir.Decl)
v := n.Left().(*ir.Name) v := n.Left().(*ir.Name)
if v.Class() == ir.PAUTOHEAP { if v.Class() == ir.PAUTOHEAP {
if base.Flag.CompilingRuntime { if base.Flag.CompilingRuntime {
@ -217,6 +220,7 @@ func walkstmt(n ir.Node) ir.Node {
return n return n
case ir.OBLOCK: case ir.OBLOCK:
n := n.(*ir.BlockStmt)
walkstmtlist(n.List().Slice()) walkstmtlist(n.List().Slice())
return n return n
@ -225,6 +229,7 @@ func walkstmt(n ir.Node) ir.Node {
panic("unreachable") panic("unreachable")
case ir.ODEFER: case ir.ODEFER:
n := n.(*ir.GoDeferStmt)
Curfn.SetHasDefer(true) Curfn.SetHasDefer(true)
Curfn.NumDefers++ Curfn.NumDefers++
if Curfn.NumDefers > maxOpenDefers { if Curfn.NumDefers > maxOpenDefers {
@ -240,6 +245,7 @@ func walkstmt(n ir.Node) ir.Node {
} }
fallthrough fallthrough
case ir.OGO: case ir.OGO:
n := n.(*ir.GoDeferStmt)
var init ir.Nodes var init ir.Nodes
switch call := n.Left(); call.Op() { switch call := n.Left(); call.Op() {
case ir.OPRINT, ir.OPRINTN: case ir.OPRINT, ir.OPRINTN:
@ -276,6 +282,7 @@ func walkstmt(n ir.Node) ir.Node {
return n return n
case ir.OFOR, ir.OFORUNTIL: case ir.OFOR, ir.OFORUNTIL:
n := n.(*ir.ForStmt)
if n.Left() != nil { if n.Left() != nil {
walkstmtlist(n.Left().Init().Slice()) walkstmtlist(n.Left().Init().Slice())
init := n.Left().Init() init := n.Left().Init()
@ -292,12 +299,14 @@ func walkstmt(n ir.Node) ir.Node {
return n return n
case ir.OIF: case ir.OIF:
n := n.(*ir.IfStmt)
n.SetLeft(walkexpr(n.Left(), n.PtrInit())) n.SetLeft(walkexpr(n.Left(), n.PtrInit()))
walkstmtlist(n.Body().Slice()) walkstmtlist(n.Body().Slice())
walkstmtlist(n.Rlist().Slice()) walkstmtlist(n.Rlist().Slice())
return n return n
case ir.ORETURN: case ir.ORETURN:
n := n.(*ir.ReturnStmt)
Curfn.NumReturns++ Curfn.NumReturns++
if n.List().Len() == 0 { if n.List().Len() == 0 {
return n return n
@ -351,9 +360,11 @@ func walkstmt(n ir.Node) ir.Node {
return n return n
case ir.ORETJMP: case ir.ORETJMP:
n := n.(*ir.BranchStmt)
return n return n
case ir.OINLMARK: case ir.OINLMARK:
n := n.(*ir.InlineMarkStmt)
return n return n
case ir.OSELECT: case ir.OSELECT:
@ -489,6 +500,7 @@ func walkexpr(n ir.Node, init *ir.Nodes) ir.Node {
} }
if n.Op() == ir.ONAME && n.(*ir.Name).Class() == ir.PAUTOHEAP { if n.Op() == ir.ONAME && n.(*ir.Name).Class() == ir.PAUTOHEAP {
n := n.(*ir.Name)
nn := ir.NewStarExpr(base.Pos, n.Name().Heapaddr) nn := ir.NewStarExpr(base.Pos, n.Name().Heapaddr)
nn.Left().MarkNonNil() nn.Left().MarkNonNil()
return walkexpr(typecheck(nn, ctxExpr), init) return walkexpr(typecheck(nn, ctxExpr), init)
@ -543,22 +555,27 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return n return n
case ir.ONOT, ir.ONEG, ir.OPLUS, ir.OBITNOT, ir.OREAL, ir.OIMAG, ir.OSPTR, ir.OITAB, ir.OIDATA: case ir.ONOT, ir.ONEG, ir.OPLUS, ir.OBITNOT, ir.OREAL, ir.OIMAG, ir.OSPTR, ir.OITAB, ir.OIDATA:
n := n.(*ir.UnaryExpr)
n.SetLeft(walkexpr(n.Left(), init)) n.SetLeft(walkexpr(n.Left(), init))
return n return n
case ir.ODOTMETH, ir.ODOTINTER: case ir.ODOTMETH, ir.ODOTINTER:
n := n.(*ir.SelectorExpr)
n.SetLeft(walkexpr(n.Left(), init)) n.SetLeft(walkexpr(n.Left(), init))
return n return n
case ir.OADDR: case ir.OADDR:
n := n.(*ir.AddrExpr)
n.SetLeft(walkexpr(n.Left(), init)) n.SetLeft(walkexpr(n.Left(), init))
return n return n
case ir.ODEREF: case ir.ODEREF:
n := n.(*ir.StarExpr)
n.SetLeft(walkexpr(n.Left(), init)) n.SetLeft(walkexpr(n.Left(), init))
return n return n
case ir.OEFACE, ir.OAND, ir.OANDNOT, ir.OSUB, ir.OMUL, ir.OADD, ir.OOR, ir.OXOR, ir.OLSH, ir.ORSH: case ir.OEFACE, ir.OAND, ir.OANDNOT, ir.OSUB, ir.OMUL, ir.OADD, ir.OOR, ir.OXOR, ir.OLSH, ir.ORSH:
n := n.(*ir.BinaryExpr)
n.SetLeft(walkexpr(n.Left(), init)) n.SetLeft(walkexpr(n.Left(), init))
n.SetRight(walkexpr(n.Right(), init)) n.SetRight(walkexpr(n.Right(), init))
return n return n
@ -570,6 +587,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return n return n
case ir.ODOTTYPE, ir.ODOTTYPE2: case ir.ODOTTYPE, ir.ODOTTYPE2:
n := n.(*ir.TypeAssertExpr)
n.SetLeft(walkexpr(n.Left(), init)) n.SetLeft(walkexpr(n.Left(), init))
// Set up interface type addresses for back end. // Set up interface type addresses for back end.
n.SetRight(typename(n.Type())) n.SetRight(typename(n.Type()))
@ -582,6 +600,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return n return n
case ir.OLEN, ir.OCAP: case ir.OLEN, ir.OCAP:
n := n.(*ir.UnaryExpr)
if isRuneCount(n) { if isRuneCount(n) {
// Replace len([]rune(string)) with runtime.countrunes(string). // Replace len([]rune(string)) with runtime.countrunes(string).
return mkcall("countrunes", n.Type(), init, conv(n.Left().(*ir.ConvExpr).Left(), types.Types[types.TSTRING])) return mkcall("countrunes", n.Type(), init, conv(n.Left().(*ir.ConvExpr).Left(), types.Types[types.TSTRING]))
@ -605,6 +624,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return n return n
case ir.OCOMPLEX: case ir.OCOMPLEX:
n := n.(*ir.BinaryExpr)
n.SetLeft(walkexpr(n.Left(), init)) n.SetLeft(walkexpr(n.Left(), init))
n.SetRight(walkexpr(n.Right(), init)) n.SetRight(walkexpr(n.Right(), init))
return n return n
@ -614,6 +634,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return walkcompare(n, init) return walkcompare(n, init)
case ir.OANDAND, ir.OOROR: case ir.OANDAND, ir.OOROR:
n := n.(*ir.LogicalExpr)
n.SetLeft(walkexpr(n.Left(), init)) n.SetLeft(walkexpr(n.Left(), init))
// cannot put side effects from n.Right on init, // cannot put side effects from n.Right on init,
@ -629,9 +650,11 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return walkprint(n.(*ir.CallExpr), init) return walkprint(n.(*ir.CallExpr), init)
case ir.OPANIC: case ir.OPANIC:
n := n.(*ir.UnaryExpr)
return mkcall("gopanic", nil, init, n.Left()) return mkcall("gopanic", nil, init, n.Left())
case ir.ORECOVER: case ir.ORECOVER:
n := n.(*ir.CallExpr)
return mkcall("gorecover", n.Type(), init, nodAddr(nodfp)) return mkcall("gorecover", n.Type(), init, nodAddr(nodfp))
case ir.OCLOSUREREAD, ir.OCFUNC: case ir.OCLOSUREREAD, ir.OCFUNC:
@ -674,8 +697,10 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
var left, right ir.Node var left, right ir.Node
switch n.Op() { switch n.Op() {
case ir.OAS: case ir.OAS:
n := n.(*ir.AssignStmt)
left, right = n.Left(), n.Right() left, right = n.Left(), n.Right()
case ir.OASOP: case ir.OASOP:
n := n.(*ir.AssignOpStmt)
left, right = n.Left(), n.Right() left, right = n.Left(), n.Right()
} }
@ -683,6 +708,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
// the mapassign call. // the mapassign call.
var mapAppend *ir.CallExpr var mapAppend *ir.CallExpr
if left.Op() == ir.OINDEXMAP && right.Op() == ir.OAPPEND { if left.Op() == ir.OINDEXMAP && right.Op() == ir.OAPPEND {
left := left.(*ir.IndexExpr)
mapAppend = right.(*ir.CallExpr) mapAppend = right.(*ir.CallExpr)
if !samesafeexpr(left, mapAppend.List().First()) { if !samesafeexpr(left, mapAppend.List().First()) {
base.Fatalf("not same expressions: %v != %v", left, mapAppend.List().First()) base.Fatalf("not same expressions: %v != %v", left, mapAppend.List().First())
@ -764,6 +790,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return as return as
case ir.OAS2: case ir.OAS2:
n := n.(*ir.AssignListStmt)
init.AppendNodes(n.PtrInit()) init.AppendNodes(n.PtrInit())
walkexprlistsafe(n.List().Slice(), init) walkexprlistsafe(n.List().Slice(), init)
walkexprlistsafe(n.Rlist().Slice(), init) walkexprlistsafe(n.Rlist().Slice(), init)
@ -771,6 +798,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
// a,b,... = fn() // a,b,... = fn()
case ir.OAS2FUNC: case ir.OAS2FUNC:
n := n.(*ir.AssignListStmt)
init.AppendNodes(n.PtrInit()) init.AppendNodes(n.PtrInit())
r := n.Rlist().First() r := n.Rlist().First()
@ -789,6 +817,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
// x, y = <-c // x, y = <-c
// order.stmt made sure x is addressable or blank. // order.stmt made sure x is addressable or blank.
case ir.OAS2RECV: case ir.OAS2RECV:
n := n.(*ir.AssignListStmt)
init.AppendNodes(n.PtrInit()) init.AppendNodes(n.PtrInit())
r := n.Rlist().First().(*ir.UnaryExpr) // recv r := n.Rlist().First().(*ir.UnaryExpr) // recv
@ -807,6 +836,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
// a,b = m[i] // a,b = m[i]
case ir.OAS2MAPR: case ir.OAS2MAPR:
n := n.(*ir.AssignListStmt)
init.AppendNodes(n.PtrInit()) init.AppendNodes(n.PtrInit())
r := n.Rlist().First().(*ir.IndexExpr) r := n.Rlist().First().(*ir.IndexExpr)
@ -868,6 +898,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return walkexpr(typecheck(as, ctxStmt), init) return walkexpr(typecheck(as, ctxStmt), init)
case ir.ODELETE: case ir.ODELETE:
n := n.(*ir.CallExpr)
init.AppendNodes(n.PtrInit()) init.AppendNodes(n.PtrInit())
map_ := n.List().First() map_ := n.List().First()
key := n.List().Second() key := n.List().Second()
@ -883,11 +914,13 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return mkcall1(mapfndel(mapdelete[fast], t), nil, init, typename(t), map_, key) return mkcall1(mapfndel(mapdelete[fast], t), nil, init, typename(t), map_, key)
case ir.OAS2DOTTYPE: case ir.OAS2DOTTYPE:
n := n.(*ir.AssignListStmt)
walkexprlistsafe(n.List().Slice(), init) walkexprlistsafe(n.List().Slice(), init)
n.PtrRlist().SetIndex(0, walkexpr(n.Rlist().First(), init)) n.PtrRlist().SetIndex(0, walkexpr(n.Rlist().First(), init))
return n return n
case ir.OCONVIFACE: case ir.OCONVIFACE:
n := n.(*ir.ConvExpr)
n.SetLeft(walkexpr(n.Left(), init)) n.SetLeft(walkexpr(n.Left(), init))
fromType := n.Left().Type() fromType := n.Left().Type()
@ -1061,6 +1094,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return conv(mkcall(fn, types.Types[result], init, conv(n.Left(), types.Types[param])), n.Type()) return conv(mkcall(fn, types.Types[result], init, conv(n.Left(), types.Types[param])), n.Type())
case ir.ODIV, ir.OMOD: case ir.ODIV, ir.OMOD:
n := n.(*ir.BinaryExpr)
n.SetLeft(walkexpr(n.Left(), init)) n.SetLeft(walkexpr(n.Left(), init))
n.SetRight(walkexpr(n.Right(), init)) n.SetRight(walkexpr(n.Right(), init))
@ -1120,6 +1154,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return n return n
case ir.OINDEX: case ir.OINDEX:
n := n.(*ir.IndexExpr)
n.SetLeft(walkexpr(n.Left(), init)) n.SetLeft(walkexpr(n.Left(), init))
// save the original node for bounds checking elision. // save the original node for bounds checking elision.
@ -1164,6 +1199,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
case ir.OINDEXMAP: case ir.OINDEXMAP:
// Replace m[k] with *map{access1,assign}(maptype, m, &k) // Replace m[k] with *map{access1,assign}(maptype, m, &k)
n := n.(*ir.IndexExpr)
n.SetLeft(walkexpr(n.Left(), init)) n.SetLeft(walkexpr(n.Left(), init))
n.SetRight(walkexpr(n.Right(), init)) n.SetRight(walkexpr(n.Right(), init))
map_ := n.Left() map_ := n.Left()
@ -1207,6 +1243,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
panic("unreachable") panic("unreachable")
case ir.OSLICEHEADER: case ir.OSLICEHEADER:
n := n.(*ir.SliceHeaderExpr)
n.SetLeft(walkexpr(n.Left(), init)) n.SetLeft(walkexpr(n.Left(), init))
n.List().SetFirst(walkexpr(n.List().First(), init)) n.List().SetFirst(walkexpr(n.List().First(), init))
n.List().SetSecond(walkexpr(n.List().Second(), init)) n.List().SetSecond(walkexpr(n.List().Second(), init))
@ -1251,6 +1288,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return reduceSlice(n) return reduceSlice(n)
case ir.ONEW: case ir.ONEW:
n := n.(*ir.UnaryExpr)
if n.Type().Elem().NotInHeap() { if n.Type().Elem().NotInHeap() {
base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", n.Type().Elem()) base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", n.Type().Elem())
} }
@ -1277,6 +1315,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
case ir.OCLOSE: case ir.OCLOSE:
// cannot use chanfn - closechan takes any, not chan any // cannot use chanfn - closechan takes any, not chan any
n := n.(*ir.UnaryExpr)
fn := syslook("closechan") fn := syslook("closechan")
fn = substArgTypes(fn, n.Left().Type()) fn = substArgTypes(fn, n.Left().Type())
return mkcall1(fn, nil, init, n.Left()) return mkcall1(fn, nil, init, n.Left())
@ -1284,6 +1323,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
case ir.OMAKECHAN: case ir.OMAKECHAN:
// When size fits into int, use makechan instead of // When size fits into int, use makechan instead of
// makechan64, which is faster and shorter on 32 bit platforms. // makechan64, which is faster and shorter on 32 bit platforms.
n := n.(*ir.MakeExpr)
size := n.Left() size := n.Left()
fnname := "makechan64" fnname := "makechan64"
argtype := types.Types[types.TINT64] argtype := types.Types[types.TINT64]
@ -1299,6 +1339,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return mkcall1(chanfn(fnname, 1, n.Type()), n.Type(), init, typename(n.Type()), conv(size, argtype)) return mkcall1(chanfn(fnname, 1, n.Type()), n.Type(), init, typename(n.Type()), conv(size, argtype))
case ir.OMAKEMAP: case ir.OMAKEMAP:
n := n.(*ir.MakeExpr)
t := n.Type() t := n.Type()
hmapType := hmap(t) hmapType := hmap(t)
hint := n.Left() hint := n.Left()
@ -1400,6 +1441,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return mkcall1(fn, n.Type(), init, typename(n.Type()), conv(hint, argtype), h) return mkcall1(fn, n.Type(), init, typename(n.Type()), conv(hint, argtype), h)
case ir.OMAKESLICE: case ir.OMAKESLICE:
n := n.(*ir.MakeExpr)
l := n.Left() l := n.Left()
r := n.Right() r := n.Right()
if r == nil { if r == nil {
@ -1471,6 +1513,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return walkexpr(typecheck(m, ctxExpr), init) return walkexpr(typecheck(m, ctxExpr), init)
case ir.OMAKESLICECOPY: case ir.OMAKESLICECOPY:
n := n.(*ir.MakeExpr)
if n.Esc() == EscNone { if n.Esc() == EscNone {
base.Fatalf("OMAKESLICECOPY with EscNone: %v", n) base.Fatalf("OMAKESLICECOPY with EscNone: %v", n)
} }
@ -1525,6 +1568,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return walkexpr(typecheck(s, ctxExpr), init) return walkexpr(typecheck(s, ctxExpr), init)
case ir.ORUNESTR: case ir.ORUNESTR:
n := n.(*ir.ConvExpr)
a := nodnil() a := nodnil()
if n.Esc() == EscNone { if n.Esc() == EscNone {
t := types.NewArray(types.Types[types.TUINT8], 4) t := types.NewArray(types.Types[types.TUINT8], 4)
@ -1534,6 +1578,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return mkcall("intstring", n.Type(), init, a, conv(n.Left(), types.Types[types.TINT64])) return mkcall("intstring", n.Type(), init, a, conv(n.Left(), types.Types[types.TINT64]))
case ir.OBYTES2STR, ir.ORUNES2STR: case ir.OBYTES2STR, ir.ORUNES2STR:
n := n.(*ir.ConvExpr)
a := nodnil() a := nodnil()
if n.Esc() == EscNone { if n.Esc() == EscNone {
// Create temporary buffer for string on stack. // Create temporary buffer for string on stack.
@ -1550,6 +1595,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return mkcall("slicebytetostring", n.Type(), init, a, ptr, len) return mkcall("slicebytetostring", n.Type(), init, a, ptr, len)
case ir.OBYTES2STRTMP: case ir.OBYTES2STRTMP:
n := n.(*ir.ConvExpr)
n.SetLeft(walkexpr(n.Left(), init)) n.SetLeft(walkexpr(n.Left(), init))
if !instrumenting { if !instrumenting {
// Let the backend handle OBYTES2STRTMP directly // Let the backend handle OBYTES2STRTMP directly
@ -1562,6 +1608,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return mkcall("slicebytetostringtmp", n.Type(), init, ptr, len) return mkcall("slicebytetostringtmp", n.Type(), init, ptr, len)
case ir.OSTR2BYTES: case ir.OSTR2BYTES:
n := n.(*ir.ConvExpr)
s := n.Left() s := n.Left()
if ir.IsConst(s, constant.String) { if ir.IsConst(s, constant.String) {
sc := ir.StringVal(s) sc := ir.StringVal(s)
@ -1607,10 +1654,12 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
// that know that the slice won't be mutated. // that know that the slice won't be mutated.
// The only such case today is: // The only such case today is:
// for i, c := range []byte(string) // for i, c := range []byte(string)
n := n.(*ir.ConvExpr)
n.SetLeft(walkexpr(n.Left(), init)) n.SetLeft(walkexpr(n.Left(), init))
return n return n
case ir.OSTR2RUNES: case ir.OSTR2RUNES:
n := n.(*ir.ConvExpr)
a := nodnil() a := nodnil()
if n.Esc() == EscNone { if n.Esc() == EscNone {
// Create temporary buffer for slice on stack. // Create temporary buffer for slice on stack.
@ -1634,6 +1683,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
return var_ return var_
case ir.OSEND: case ir.OSEND:
n := n.(*ir.SendStmt)
n1 := n.Right() n1 := n.Right()
n1 = assignconv(n1, n.Left().Type().Elem(), "chan send") n1 = assignconv(n1, n.Left().Type().Elem(), "chan send")
n1 = walkexpr(n1, init) n1 = walkexpr(n1, init)
@ -2100,8 +2150,10 @@ func isReflectHeaderDataField(l ir.Node) bool {
var tsym *types.Sym var tsym *types.Sym
switch l.Op() { switch l.Op() {
case ir.ODOT: case ir.ODOT:
l := l.(*ir.SelectorExpr)
tsym = l.Left().Type().Sym() tsym = l.Left().Type().Sym()
case ir.ODOTPTR: case ir.ODOTPTR:
l := l.(*ir.SelectorExpr)
tsym = l.Left().Type().Elem().Sym() tsym = l.Left().Type().Elem().Sym()
default: default:
return false return false
@ -2167,12 +2219,15 @@ func reorder3(all []*ir.AssignStmt) []ir.Node {
for { for {
switch ll := l; ll.Op() { switch ll := l; ll.Op() {
case ir.ODOT: case ir.ODOT:
ll := ll.(*ir.SelectorExpr)
l = ll.Left() l = ll.Left()
continue continue
case ir.OPAREN: case ir.OPAREN:
ll := ll.(*ir.ParenExpr)
l = ll.Left() l = ll.Left()
continue continue
case ir.OINDEX: case ir.OINDEX:
ll := ll.(*ir.IndexExpr)
if ll.Left().Type().IsArray() { if ll.Left().Type().IsArray() {
ll.SetRight(reorder3save(ll.Right(), all, i, &early)) ll.SetRight(reorder3save(ll.Right(), all, i, &early))
l = ll.Left() l = ll.Left()
@ -2190,6 +2245,7 @@ func reorder3(all []*ir.AssignStmt) []ir.Node {
break break
case ir.OINDEX, ir.OINDEXMAP: case ir.OINDEX, ir.OINDEXMAP:
l := l.(*ir.IndexExpr)
l.SetLeft(reorder3save(l.Left(), all, i, &early)) l.SetLeft(reorder3save(l.Left(), all, i, &early))
l.SetRight(reorder3save(l.Right(), all, i, &early)) l.SetRight(reorder3save(l.Right(), all, i, &early))
if l.Op() == ir.OINDEXMAP { if l.Op() == ir.OINDEXMAP {
@ -2197,8 +2253,10 @@ func reorder3(all []*ir.AssignStmt) []ir.Node {
} }
case ir.ODEREF: case ir.ODEREF:
l := l.(*ir.StarExpr)
l.SetLeft(reorder3save(l.Left(), all, i, &early)) l.SetLeft(reorder3save(l.Left(), all, i, &early))
case ir.ODOTPTR: case ir.ODOTPTR:
l := l.(*ir.SelectorExpr)
l.SetLeft(reorder3save(l.Left(), all, i, &early)) l.SetLeft(reorder3save(l.Left(), all, i, &early))
} }
@ -2238,15 +2296,19 @@ func outervalue(n ir.Node) ir.Node {
case ir.OXDOT: case ir.OXDOT:
base.Fatalf("OXDOT in walk") base.Fatalf("OXDOT in walk")
case ir.ODOT: case ir.ODOT:
nn := nn.(*ir.SelectorExpr)
n = nn.Left() n = nn.Left()
continue continue
case ir.OPAREN: case ir.OPAREN:
nn := nn.(*ir.ParenExpr)
n = nn.Left() n = nn.Left()
continue continue
case ir.OCONVNOP: case ir.OCONVNOP:
nn := nn.(*ir.ConvExpr)
n = nn.Left() n = nn.Left()
continue continue
case ir.OINDEX: case ir.OINDEX:
nn := nn.(*ir.IndexExpr)
if nn.Left().Type() != nil && nn.Left().Type().IsArray() { if nn.Left().Type() != nil && nn.Left().Type().IsArray() {
n = nn.Left() n = nn.Left()
continue continue
@ -2338,6 +2400,7 @@ func anyAddrTaken(n ir.Node) bool {
return ir.Any(n, func(n ir.Node) bool { return ir.Any(n, func(n ir.Node) bool {
switch n.Op() { switch n.Op() {
case ir.ONAME: case ir.ONAME:
n := n.(*ir.Name)
return n.Class() == ir.PEXTERN || n.Class() == ir.PAUTOHEAP || n.Name().Addrtaken() return n.Class() == ir.PEXTERN || n.Class() == ir.PAUTOHEAP || n.Name().Addrtaken()
case ir.ODOT: // but not ODOTPTR - should have been handled in aliased. case ir.ODOT: // but not ODOTPTR - should have been handled in aliased.
@ -2420,6 +2483,7 @@ func refersToCommonName(l ir.Node, r ir.Node) bool {
} }
doL = func(l ir.Node) error { doL = func(l ir.Node) error {
if l.Op() == ir.ONAME { if l.Op() == ir.ONAME {
l := l.(*ir.Name)
targetL = l.Name() targetL = l.Name()
if doR(r) == stop { if doR(r) == stop {
return stop return stop
@ -3635,6 +3699,7 @@ func bounded(n ir.Node, max int64) bool {
switch n.Op() { switch n.Op() {
case ir.OAND, ir.OANDNOT: case ir.OAND, ir.OANDNOT:
n := n.(*ir.BinaryExpr)
v := int64(-1) v := int64(-1)
switch { switch {
case smallintconst(n.Left()): case smallintconst(n.Left()):
@ -3653,6 +3718,7 @@ func bounded(n ir.Node, max int64) bool {
} }
case ir.OMOD: case ir.OMOD:
n := n.(*ir.BinaryExpr)
if !sign && smallintconst(n.Right()) { if !sign && smallintconst(n.Right()) {
v := ir.Int64Val(n.Right()) v := ir.Int64Val(n.Right())
if 0 <= v && v <= max { if 0 <= v && v <= max {
@ -3661,6 +3727,7 @@ func bounded(n ir.Node, max int64) bool {
} }
case ir.ODIV: case ir.ODIV:
n := n.(*ir.BinaryExpr)
if !sign && smallintconst(n.Right()) { if !sign && smallintconst(n.Right()) {
v := ir.Int64Val(n.Right()) v := ir.Int64Val(n.Right())
for bits > 0 && v >= 2 { for bits > 0 && v >= 2 {
@ -3670,6 +3737,7 @@ func bounded(n ir.Node, max int64) bool {
} }
case ir.ORSH: case ir.ORSH:
n := n.(*ir.BinaryExpr)
if !sign && smallintconst(n.Right()) { if !sign && smallintconst(n.Right()) {
v := ir.Int64Val(n.Right()) v := ir.Int64Val(n.Right())
if v > int64(bits) { if v > int64(bits) {
@ -3849,6 +3917,7 @@ func anySideEffects(n ir.Node) bool {
// Only possible side effect is division by zero. // Only possible side effect is division by zero.
case ir.ODIV, ir.OMOD: case ir.ODIV, ir.OMOD:
n := n.(*ir.BinaryExpr)
if n.Right().Op() != ir.OLITERAL || constant.Sign(n.Right().Val()) == 0 { if n.Right().Op() != ir.OLITERAL || constant.Sign(n.Right().Val()) == 0 {
return true return true
} }
@ -3856,6 +3925,7 @@ func anySideEffects(n ir.Node) bool {
// Only possible side effect is panic on invalid size, // Only possible side effect is panic on invalid size,
// but many makechan and makemap use size zero, which is definitely OK. // but many makechan and makemap use size zero, which is definitely OK.
case ir.OMAKECHAN, ir.OMAKEMAP: case ir.OMAKECHAN, ir.OMAKEMAP:
n := n.(*ir.MakeExpr)
if !ir.IsConst(n.Left(), constant.Int) || constant.Sign(n.Left().Val()) != 0 { if !ir.IsConst(n.Left(), constant.Int) || constant.Sign(n.Left().Val()) != 0 {
return true return true
} }
@ -3901,6 +3971,7 @@ func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
if !isBuiltinCall && n.IsDDD() { if !isBuiltinCall && n.IsDDD() {
last := n.List().Len() - 1 last := n.List().Len() - 1
if va := n.List().Index(last); va.Op() == ir.OSLICELIT { if va := n.List().Index(last); va.Op() == ir.OSLICELIT {
va := va.(*ir.CompLitExpr)
n.PtrList().Set(append(n.List().Slice()[:last], va.List().Slice()...)) n.PtrList().Set(append(n.List().Slice()[:last], va.List().Slice()...))
n.SetIsDDD(false) n.SetIsDDD(false)
} }
@ -4051,11 +4122,14 @@ func walkCheckPtrArithmetic(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
walk = func(n ir.Node) { walk = func(n ir.Node) {
switch n.Op() { switch n.Op() {
case ir.OADD: case ir.OADD:
n := n.(*ir.BinaryExpr)
walk(n.Left()) walk(n.Left())
walk(n.Right()) walk(n.Right())
case ir.OSUB, ir.OANDNOT: case ir.OSUB, ir.OANDNOT:
n := n.(*ir.BinaryExpr)
walk(n.Left()) walk(n.Left())
case ir.OCONVNOP: case ir.OCONVNOP:
n := n.(*ir.ConvExpr)
if n.Left().Type().IsUnsafePtr() { if n.Left().Type().IsUnsafePtr() {
n.SetLeft(cheapexpr(n.Left(), init)) n.SetLeft(cheapexpr(n.Left(), init))
originals = append(originals, convnop(n.Left(), types.Types[types.TUNSAFEPTR])) originals = append(originals, convnop(n.Left(), types.Types[types.TUNSAFEPTR]))

View file

@ -35,11 +35,6 @@ type miniNode struct {
esc uint16 esc uint16
} }
func (n *miniNode) Format(s fmt.State, verb rune) { panic(1) }
func (n *miniNode) copy() Node { panic(1) }
func (n *miniNode) doChildren(do func(Node) error) error { panic(1) }
func (n *miniNode) editChildren(edit func(Node) Node) { panic(1) }
// posOr returns pos if known, or else n.pos. // posOr returns pos if known, or else n.pos.
// For use in DeepCopy. // For use in DeepCopy.
func (n *miniNode) posOr(pos src.XPos) src.XPos { func (n *miniNode) posOr(pos src.XPos) src.XPos {
@ -85,106 +80,27 @@ func (n *miniNode) SetDiag(x bool) { n.bits.set(miniDiag, x) }
// Empty, immutable graph structure. // Empty, immutable graph structure.
func (n *miniNode) Left() Node { return nil }
func (n *miniNode) Right() Node { return nil }
func (n *miniNode) Init() Nodes { return Nodes{} } func (n *miniNode) Init() Nodes { return Nodes{} }
func (n *miniNode) PtrInit() *Nodes { return &immutableEmptyNodes } func (n *miniNode) PtrInit() *Nodes { return &immutableEmptyNodes }
func (n *miniNode) Body() Nodes { return Nodes{} }
func (n *miniNode) PtrBody() *Nodes { return &immutableEmptyNodes }
func (n *miniNode) List() Nodes { return Nodes{} }
func (n *miniNode) PtrList() *Nodes { return &immutableEmptyNodes }
func (n *miniNode) Rlist() Nodes { return Nodes{} }
func (n *miniNode) PtrRlist() *Nodes { return &immutableEmptyNodes }
func (n *miniNode) SetLeft(x Node) {
if x != nil {
panic(n.no("SetLeft"))
}
}
func (n *miniNode) SetRight(x Node) {
if x != nil {
panic(n.no("SetRight"))
}
}
func (n *miniNode) SetInit(x Nodes) { func (n *miniNode) SetInit(x Nodes) {
if x != nil { if x != nil {
panic(n.no("SetInit")) panic(n.no("SetInit"))
} }
} }
func (n *miniNode) SetBody(x Nodes) {
if x != nil {
panic(n.no("SetBody"))
}
}
func (n *miniNode) SetList(x Nodes) {
if x != nil {
panic(n.no("SetList"))
}
}
func (n *miniNode) SetRlist(x Nodes) {
if x != nil {
panic(n.no("SetRlist"))
}
}
// Additional functionality unavailable. // Additional functionality unavailable.
func (n *miniNode) no(name string) string { return "cannot " + name + " on " + n.op.String() } func (n *miniNode) no(name string) string { return "cannot " + name + " on " + n.op.String() }
func (n *miniNode) SetOp(Op) { panic(n.no("SetOp")) }
func (n *miniNode) SubOp() Op { panic(n.no("SubOp")) }
func (n *miniNode) SetSubOp(Op) { panic(n.no("SetSubOp")) }
func (n *miniNode) Type() *types.Type { return nil } func (n *miniNode) Type() *types.Type { return nil }
func (n *miniNode) SetType(*types.Type) { panic(n.no("SetType")) } func (n *miniNode) SetType(*types.Type) { panic(n.no("SetType")) }
func (n *miniNode) Func() *Func { return nil }
func (n *miniNode) Name() *Name { return nil } func (n *miniNode) Name() *Name { return nil }
func (n *miniNode) Sym() *types.Sym { return nil } func (n *miniNode) Sym() *types.Sym { return nil }
func (n *miniNode) SetSym(*types.Sym) { panic(n.no("SetSym")) }
func (n *miniNode) Offset() int64 { return types.BADWIDTH }
func (n *miniNode) SetOffset(x int64) { panic(n.no("SetOffset")) }
func (n *miniNode) Class() Class { return Pxxx }
func (n *miniNode) SetClass(Class) { panic(n.no("SetClass")) }
func (n *miniNode) Likely() bool { panic(n.no("Likely")) }
func (n *miniNode) SetLikely(bool) { panic(n.no("SetLikely")) }
func (n *miniNode) SliceBounds() (low, high, max Node) {
panic(n.no("SliceBounds"))
}
func (n *miniNode) SetSliceBounds(low, high, max Node) {
panic(n.no("SetSliceBounds"))
}
func (n *miniNode) Iota() int64 { panic(n.no("Iota")) }
func (n *miniNode) SetIota(int64) { panic(n.no("SetIota")) }
func (n *miniNode) Colas() bool { return false }
func (n *miniNode) SetColas(bool) { panic(n.no("SetColas")) }
func (n *miniNode) NoInline() bool { panic(n.no("NoInline")) }
func (n *miniNode) SetNoInline(bool) { panic(n.no("SetNoInline")) }
func (n *miniNode) Transient() bool { panic(n.no("Transient")) }
func (n *miniNode) SetTransient(bool) { panic(n.no("SetTransient")) }
func (n *miniNode) Implicit() bool { return false }
func (n *miniNode) SetImplicit(bool) { panic(n.no("SetImplicit")) }
func (n *miniNode) IsDDD() bool { return false }
func (n *miniNode) SetIsDDD(bool) { panic(n.no("SetIsDDD")) }
func (n *miniNode) Embedded() bool { return false }
func (n *miniNode) SetEmbedded(bool) { panic(n.no("SetEmbedded")) }
func (n *miniNode) IndexMapLValue() bool { panic(n.no("IndexMapLValue")) }
func (n *miniNode) SetIndexMapLValue(bool) { panic(n.no("SetIndexMapLValue")) }
func (n *miniNode) ResetAux() { panic(n.no("ResetAux")) }
func (n *miniNode) HasBreak() bool { panic(n.no("HasBreak")) }
func (n *miniNode) SetHasBreak(bool) { panic(n.no("SetHasBreak")) }
func (n *miniNode) Val() constant.Value { panic(n.no("Val")) } func (n *miniNode) Val() constant.Value { panic(n.no("Val")) }
func (n *miniNode) SetVal(v constant.Value) { panic(n.no("SetVal")) } func (n *miniNode) SetVal(v constant.Value) { panic(n.no("SetVal")) }
func (n *miniNode) Int64Val() int64 { panic(n.no("Int64Val")) }
func (n *miniNode) Uint64Val() uint64 { panic(n.no("Uint64Val")) }
func (n *miniNode) CanInt64() bool { panic(n.no("CanInt64")) }
func (n *miniNode) BoolVal() bool { panic(n.no("BoolVal")) }
func (n *miniNode) StringVal() string { panic(n.no("StringVal")) }
func (n *miniNode) HasCall() bool { return false } func (n *miniNode) HasCall() bool { return false }
func (n *miniNode) SetHasCall(bool) { panic(n.no("SetHasCall")) } func (n *miniNode) SetHasCall(bool) { panic(n.no("SetHasCall")) }
func (n *miniNode) NonNil() bool { return false } func (n *miniNode) NonNil() bool { return false }
func (n *miniNode) MarkNonNil() { panic(n.no("MarkNonNil")) } func (n *miniNode) MarkNonNil() { panic(n.no("MarkNonNil")) }
func (n *miniNode) Bounded() bool { return false }
func (n *miniNode) SetBounded(bool) { panic(n.no("SetBounded")) }
func (n *miniNode) Opt() interface{} { return nil } func (n *miniNode) Opt() interface{} { return nil }
func (n *miniNode) SetOpt(interface{}) { panic(n.no("SetOpt")) } func (n *miniNode) SetOpt(interface{}) { panic(n.no("SetOpt")) }
func (n *miniNode) MarkReadonly() { panic(n.no("MarkReadonly")) }
func (n *miniNode) TChanDir() types.ChanDir { panic(n.no("TChanDir")) }
func (n *miniNode) SetTChanDir(types.ChanDir) { panic(n.no("SetTChanDir")) }

View file

@ -33,59 +33,15 @@ type Node interface {
// Abstract graph structure, for generic traversals. // Abstract graph structure, for generic traversals.
Op() Op Op() Op
SetOp(x Op)
SubOp() Op
SetSubOp(x Op)
Left() Node
SetLeft(x Node)
Right() Node
SetRight(x Node)
Init() Nodes Init() Nodes
PtrInit() *Nodes PtrInit() *Nodes
SetInit(x Nodes) SetInit(x Nodes)
Body() Nodes
PtrBody() *Nodes
SetBody(x Nodes)
List() Nodes
SetList(x Nodes)
PtrList() *Nodes
Rlist() Nodes
SetRlist(x Nodes)
PtrRlist() *Nodes
// Fields specific to certain Ops only. // Fields specific to certain Ops only.
Type() *types.Type Type() *types.Type
SetType(t *types.Type) SetType(t *types.Type)
Func() *Func
Name() *Name Name() *Name
Sym() *types.Sym Sym() *types.Sym
SetSym(x *types.Sym)
Offset() int64
SetOffset(x int64)
Class() Class
SetClass(x Class)
Likely() bool
SetLikely(x bool)
SliceBounds() (low, high, max Node)
SetSliceBounds(low, high, max Node)
Iota() int64
SetIota(x int64)
Colas() bool
SetColas(x bool)
NoInline() bool
SetNoInline(x bool)
Transient() bool
SetTransient(x bool)
Implicit() bool
SetImplicit(x bool)
IsDDD() bool
SetIsDDD(x bool)
IndexMapLValue() bool
SetIndexMapLValue(x bool)
ResetAux()
HasBreak() bool
SetHasBreak(x bool)
MarkReadonly()
Val() constant.Value Val() constant.Value
SetVal(v constant.Value) SetVal(v constant.Value)
@ -98,8 +54,6 @@ type Node interface {
SetOpt(x interface{}) SetOpt(x interface{})
Diag() bool Diag() bool
SetDiag(x bool) SetDiag(x bool)
Bounded() bool
SetBounded(x bool)
Typecheck() uint8 Typecheck() uint8
SetTypecheck(x uint8) SetTypecheck(x uint8)
NonNil() bool NonNil() bool