1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/ir"
12 // The result of walkStmt MUST be assigned back to n, e.g.
14 // n.Left = walkStmt(n.Left)
15 func walkStmt(n ir.Node) ir.Node {
22 walkStmtList(n.Init())
26 if n.Op() == ir.ONAME {
28 base.Errorf("%v is not a top level statement", n.Sym())
30 base.Errorf("%v is not a top level statement", n.Op())
55 if n.Typecheck() == 0 {
56 base.Fatalf("missing typecheck: %+v", n)
59 init := ir.TakeInit(n)
60 n = walkExpr(n, &init)
61 if n.Op() == ir.ONAME {
62 // copy rewrote to a statement list and a temp for the length.
63 // Throw away the temp to avoid plain values as statements.
64 n = ir.NewBlockStmt(n.Pos(), init)
69 case ir.OAS, ir.OAS2, ir.OBLOCK:
70 n.(ir.InitNode).PtrInit().Prepend(init...)
74 n = ir.NewBlockStmt(n.Pos(), init)
79 // special case for a receive where we throw away
80 // the value received.
82 n := n.(*ir.UnaryExpr)
97 n := n.(*ir.BlockStmt)
102 base.Errorf("case statement out of place")
106 n := n.(*ir.GoDeferStmt)
107 ir.CurFunc.SetHasDefer(true)
108 ir.CurFunc.NumDefers++
109 if ir.CurFunc.NumDefers > maxOpenDefers || n.DeferAt != nil {
110 // Don't allow open-coded defers if there are more than
111 // 8 defers in the function, since we use a single
112 // byte to record active defers.
113 // Also don't allow if we need to use deferprocat.
114 ir.CurFunc.SetOpenCodedDeferDisallowed(true)
116 if n.Esc() != ir.EscNever {
117 // If n.Esc is not EscNever, then this defer occurs in a loop,
118 // so open-coded defers cannot be used in this function.
119 ir.CurFunc.SetOpenCodedDeferDisallowed(true)
123 n := n.(*ir.GoDeferStmt)
124 return walkGoDefer(n)
135 n := n.(*ir.ReturnStmt)
139 n := n.(*ir.TailCallStmt)
142 n.Call.Fun = walkExpr(n.Call.Fun, &init)
146 return ir.NewBlockStmt(n.Pos(), init)
151 n := n.(*ir.InlineMarkStmt)
155 n := n.(*ir.SelectStmt)
160 n := n.(*ir.SwitchStmt)
165 n := n.(*ir.RangeStmt)
169 // No return! Each case must return (or panic),
170 // to avoid confusion about what gets returned
171 // in the presence of type assertions.
174 func walkStmtList(s []ir.Node) {
176 s[i] = walkStmt(s[i])
180 // walkFor walks an OFOR node.
181 func walkFor(n *ir.ForStmt) ir.Node {
183 init := ir.TakeInit(n.Cond)
185 n.Cond = walkExpr(n.Cond, &init)
186 n.Cond = ir.InitExpr(init, n.Cond)
189 n.Post = walkStmt(n.Post)
194 // validGoDeferCall reports whether call is a valid call to appear in
195 // a go or defer statement; that is, whether it's a regular function
196 // call without arguments or results.
197 func validGoDeferCall(call ir.Node) bool {
198 if call, ok := call.(*ir.CallExpr); ok && call.Op() == ir.OCALLFUNC && len(call.KeepAlive) == 0 {
199 sig := call.Fun.Type()
200 return sig.NumParams()+sig.NumResults() == 0
205 // walkGoDefer walks an OGO or ODEFER node.
206 func walkGoDefer(n *ir.GoDeferStmt) ir.Node {
207 if !validGoDeferCall(n.Call) {
208 base.FatalfAt(n.Pos(), "invalid %v call: %v", n.Op(), n.Call)
213 call := n.Call.(*ir.CallExpr)
214 call.Fun = walkExpr(call.Fun, &init)
218 return ir.NewBlockStmt(n.Pos(), init)
223 // walkIf walks an OIF node.
224 func walkIf(n *ir.IfStmt) ir.Node {
225 n.Cond = walkExpr(n.Cond, n.PtrInit())