default:
base.Fatalf("unexpected stmt: %v", n)
- case ir.ODCLCONST, ir.ODCLTYPE, ir.OEMPTY, ir.OFALL, ir.OINLMARK:
+ case ir.ODCLCONST, ir.ODCLTYPE, ir.OFALL, ir.OINLMARK:
// nop
case ir.OBREAK, ir.OCONTINUE, ir.OGOTO:
}
switch op := n.Op(); op {
+ case ir.OBLOCK:
+ // No OBLOCK in export data.
+ // Inline content into this statement list,
+ // like the init list above.
+ // (At the moment neither the parser nor the typechecker
+ // generate OBLOCK nodes except to denote an empty
+ // function body, although that may change.)
+ for _, n := range n.List().Slice() {
+ w.stmt(n)
+ }
+
case ir.ODCL:
w.op(ir.ODCL)
w.pos(n.Left().Pos())
w.op(ir.OFALL)
w.pos(n.Pos())
- case ir.OEMPTY:
- // nothing to emit
-
case ir.OBREAK, ir.OCONTINUE, ir.OGOTO, ir.OLABEL:
w.op(op)
w.pos(n.Pos())
if n == nil {
break
}
- // OBLOCK nodes may be created when importing ODCL nodes - unpack them
+ // OBLOCK nodes are not written to the import data directly,
+ // but the handling of ODCL calls liststmt, which creates one.
+ // Inline them into the statement list.
if n.Op() == ir.OBLOCK {
list = append(list, n.List().Slice()...)
} else {
s := lookupN("init.", i)
fn := ir.AsNode(s.Def).Name().Defn
// Skip init functions with empty bodies.
- if fn.Body().Len() == 1 && fn.Body().First().Op() == ir.OEMPTY {
- continue
+ if fn.Body().Len() == 1 {
+ if stmt := fn.Body().First(); stmt.Op() == ir.OBLOCK && stmt.List().Len() == 0 {
+ continue
+ }
}
fns = append(fns, s.Linksym())
}
case ir.OAPPEND:
v.budget -= inlineExtraAppendCost
- case ir.ODCLCONST, ir.OEMPTY, ir.OFALL:
+ case ir.ODCLCONST, ir.OFALL:
// These nodes don't produce code; omit from inlining budget.
return false
v.usedLocals[n] = true
}
+ case ir.OBLOCK:
+ // The only OBLOCK we should see at this point is an empty one.
+ // In any event, let the visitList(n.List()) below take care of the statements,
+ // and don't charge for the OBLOCK itself. The ++ undoes the -- below.
+ v.budget++
}
v.budget--
if block != nil {
body := p.stmts(block.List)
if body == nil {
- body = []ir.Node{ir.Nod(ir.OEMPTY, nil, nil)}
+ body = []ir.Node{ir.Nod(ir.OBLOCK, nil, nil)}
}
fn.PtrBody().Set(body)
for i, stmt := range stmts {
s := p.stmtFall(stmt, fallOK && i+1 == len(stmts))
if s == nil {
- } else if s.Op() == ir.OBLOCK && s.Init().Len() == 0 {
+ } else if s.Op() == ir.OBLOCK && s.List().Len() > 0 {
+ // Inline non-empty block.
+ // Empty blocks must be preserved for checkreturn.
nodes = append(nodes, s.List().Slice()...)
} else {
nodes = append(nodes, s)
l := p.blockStmt(stmt)
if len(l) == 0 {
// TODO(mdempsky): Line number?
- return ir.Nod(ir.OEMPTY, nil, nil)
+ return ir.Nod(ir.OBLOCK, nil, nil)
}
return liststmt(l)
case *syntax.ExprStmt:
n.PtrBody().Set(p.blockStmt(stmt.Then))
if stmt.Else != nil {
e := p.stmt(stmt.Else)
- if e.Op() == ir.OBLOCK && e.Init().Len() == 0 {
+ if e.Op() == ir.OBLOCK {
n.PtrRlist().Set(e.List().Slice())
} else {
n.PtrRlist().Set1(e)
l := []ir.Node{lhs}
if ls != nil {
- if ls.Op() == ir.OBLOCK && ls.Init().Len() == 0 {
+ if ls.Op() == ir.OBLOCK {
l = append(l, ls.List().Slice()...)
} else {
l = append(l, ls)
o.cleanTemp(t)
// Special: does not save n onto out.
- case ir.OBLOCK, ir.OEMPTY:
+ case ir.OBLOCK:
o.stmtList(n.List())
// Special: n->left is not an expression; save as is.
s.stmtList(n.List())
// No-ops
- case ir.OEMPTY, ir.ODCLCONST, ir.ODCLTYPE, ir.OFALL:
+ case ir.ODCLCONST, ir.ODCLTYPE, ir.OFALL:
// Expression statements
case ir.OCALLFUNC:
case ir.OBREAK,
ir.OCONTINUE,
ir.ODCL,
- ir.OEMPTY,
ir.OGOTO,
ir.OFALL,
ir.OVARKILL,
ir.OVARLIVE:
ok |= ctxStmt
+ case ir.OBLOCK:
+ ok |= ctxStmt
+ typecheckslice(n.List().Slice(), ctxStmt)
+
case ir.OLABEL:
ok |= ctxStmt
decldepth++
// Empty identifier is valid but useless.
// Eliminate now to simplify life later.
// See issues 7538, 11589, 11593.
- n = ir.NodAt(n.Pos(), ir.OEMPTY, nil, nil)
+ n = ir.NodAt(n.Pos(), ir.OBLOCK, nil, nil)
}
case ir.ODEFER:
}
}
- fn.PtrBody().Set([]ir.Node{ir.Nod(ir.OEMPTY, nil, nil)})
+ fn.PtrBody().Set([]ir.Node{ir.Nod(ir.OBLOCK, nil, nil)})
}
func deadcodeslice(nn *ir.Nodes) {
ir.OPRINT,
ir.OPRINTN,
ir.OPANIC,
- ir.OEMPTY,
ir.ORECOVER,
ir.OGETG:
if n.Typecheck() == 0 {
if wascopy && n.Op() == ir.ONAME {
// copy rewrote to a statement list and a temp for the length.
// Throw away the temp to avoid plain values as statements.
- n = ir.NodAt(n.Pos(), ir.OEMPTY, nil, nil)
+ n = ir.NodAt(n.Pos(), ir.OBLOCK, nil, nil)
}
n = addinit(n, init.Slice())
ir.Dump("walk", n)
base.Fatalf("walkexpr: switch 1 unknown op %+S", n)
- case ir.ONONAME, ir.OEMPTY, ir.OGETG, ir.ONEWOBJ, ir.OMETHEXPR:
+ case ir.ONONAME, ir.OGETG, ir.ONEWOBJ, ir.OMETHEXPR:
case ir.OTYPE, ir.ONAME, ir.OLITERAL, ir.ONIL:
// TODO(mdempsky): Just return n; see discussion on CL 38655.
}
if oaslit(n, init) {
- n = ir.NodAt(n.Pos(), ir.OEMPTY, nil, nil)
+ n = ir.NodAt(n.Pos(), ir.OBLOCK, nil, nil)
break
}
typecheckslice(calls, ctxStmt)
walkexprlist(calls, init)
- r := ir.Nod(ir.OEMPTY, nil, nil)
+ r := ir.Nod(ir.OBLOCK, nil, nil)
r = typecheck(r, ctxStmt)
- r = walkexpr(r, init)
- r.PtrInit().Set(calls)
+ r = walkstmt(r)
+ r.PtrList().Set(calls)
return r
}
mode.Fprintf(s, "%.v = %.v", n.List(), n.Rlist())
}
+ case OBLOCK:
+ if n.List().Len() != 0 {
+ mode.Fprintf(s, "%v", n.List())
+ }
+
case ORETURN:
mode.Fprintf(s, "return %.v", n.List())
mode.Fprintf(s, "%#v", n.Op())
}
- case OEMPTY:
- break
-
case OLABEL:
mode.Fprintf(s, "%v: ", n.Sym())
}
OAS2MAPR: -1,
OAS2RECV: -1,
OASOP: -1,
+ OBLOCK: -1,
OBREAK: -1,
OCASE: -1,
OCONTINUE: -1,
ODCL: -1,
ODEFER: -1,
- OEMPTY: -1,
OFALL: -1,
OFOR: -1,
OFORUNTIL: -1,
OCASE
OCONTINUE // continue [Sym]
ODEFER // defer Left (Left must be call)
- OEMPTY // no-op (empty statement)
+ OEMPTY // TODO(rsc): Delete. (Use OBLOCK instead.)
OFALL // fallthrough
OFOR // for Ninit; Left; Right { Nbody }
// OFORUNTIL is like OFOR, but the test (Left) is applied after the body:
n := NewTypeAssertExpr(pos, nleft, typ)
n.SetOp(op)
return n
- case OEMPTY:
- return NewEmptyStmt(pos)
case OFOR:
return NewForStmt(pos, nil, nleft, nright, nil)
case OGO:
func (n *DeferStmt) Left() Node { return n.Call }
func (n *DeferStmt) SetLeft(x Node) { n.Call = x }
-// An EmptyStmt is an empty statement
-type EmptyStmt struct {
- miniStmt
-}
-
-func NewEmptyStmt(pos src.XPos) *EmptyStmt {
- n := &EmptyStmt{}
- n.pos = pos
- n.op = OEMPTY
- return n
-}
-
-func (n *EmptyStmt) String() string { return fmt.Sprint(n) }
-func (n *EmptyStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
-func (n *EmptyStmt) rawCopy() Node { c := *n; return &c }
-
// A ForStmt is a non-range for loop: for Init; Cond; Post { Body }
// Op can be OFOR or OFORUNTIL (!Cond).
type ForStmt struct {