1
2
3
4
5 package walk
6
7 import (
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/ir"
10 )
11
12
13
14
15 func walkStmt(n ir.Node) ir.Node {
16 if n == nil {
17 return n
18 }
19
20 ir.SetPos(n)
21
22 walkStmtList(n.Init())
23
24 switch n.Op() {
25 default:
26 if n.Op() == ir.ONAME {
27 n := n.(*ir.Name)
28 base.Errorf("%v is not a top level statement", n.Sym())
29 } else {
30 base.Errorf("%v is not a top level statement", n.Op())
31 }
32 ir.Dump("nottop", n)
33 return n
34
35 case ir.OAS,
36 ir.OASOP,
37 ir.OAS2,
38 ir.OAS2DOTTYPE,
39 ir.OAS2RECV,
40 ir.OAS2FUNC,
41 ir.OAS2MAPR,
42 ir.OCLEAR,
43 ir.OCLOSE,
44 ir.OCOPY,
45 ir.OCALLINTER,
46 ir.OCALL,
47 ir.OCALLFUNC,
48 ir.ODELETE,
49 ir.OSEND,
50 ir.OPRINT,
51 ir.OPRINTLN,
52 ir.OPANIC,
53 ir.ORECOVERFP,
54 ir.OGETG:
55 if n.Typecheck() == 0 {
56 base.Fatalf("missing typecheck: %+v", n)
57 }
58
59 init := ir.TakeInit(n)
60 n = walkExpr(n, &init)
61 if n.Op() == ir.ONAME {
62
63
64 n = ir.NewBlockStmt(n.Pos(), init)
65 init = nil
66 }
67 if len(init) > 0 {
68 switch n.Op() {
69 case ir.OAS, ir.OAS2, ir.OBLOCK:
70 n.(ir.InitNode).PtrInit().Prepend(init...)
71
72 default:
73 init.Append(n)
74 n = ir.NewBlockStmt(n.Pos(), init)
75 }
76 }
77 return n
78
79
80
81 case ir.ORECV:
82 n := n.(*ir.UnaryExpr)
83 return walkRecv(n)
84
85 case ir.OBREAK,
86 ir.OCONTINUE,
87 ir.OFALL,
88 ir.OGOTO,
89 ir.OLABEL,
90 ir.OJUMPTABLE,
91 ir.OINTERFACESWITCH,
92 ir.ODCL,
93 ir.OCHECKNIL:
94 return n
95
96 case ir.OBLOCK:
97 n := n.(*ir.BlockStmt)
98 walkStmtList(n.List)
99 return n
100
101 case ir.OCASE:
102 base.Errorf("case statement out of place")
103 panic("unreachable")
104
105 case ir.ODEFER:
106 n := n.(*ir.GoDeferStmt)
107 ir.CurFunc.SetHasDefer(true)
108 ir.CurFunc.NumDefers++
109 if ir.CurFunc.NumDefers > maxOpenDefers || n.DeferAt != nil {
110
111
112
113
114 ir.CurFunc.SetOpenCodedDeferDisallowed(true)
115 }
116 if n.Esc() != ir.EscNever {
117
118
119 ir.CurFunc.SetOpenCodedDeferDisallowed(true)
120 }
121 fallthrough
122 case ir.OGO:
123 n := n.(*ir.GoDeferStmt)
124 return walkGoDefer(n)
125
126 case ir.OFOR:
127 n := n.(*ir.ForStmt)
128 return walkFor(n)
129
130 case ir.OIF:
131 n := n.(*ir.IfStmt)
132 return walkIf(n)
133
134 case ir.ORETURN:
135 n := n.(*ir.ReturnStmt)
136 return walkReturn(n)
137
138 case ir.OTAILCALL:
139 n := n.(*ir.TailCallStmt)
140
141 var init ir.Nodes
142 n.Call.Fun = walkExpr(n.Call.Fun, &init)
143
144 if len(init) > 0 {
145 init.Append(n)
146 return ir.NewBlockStmt(n.Pos(), init)
147 }
148 return n
149
150 case ir.OINLMARK:
151 n := n.(*ir.InlineMarkStmt)
152 return n
153
154 case ir.OSELECT:
155 n := n.(*ir.SelectStmt)
156 walkSelect(n)
157 return n
158
159 case ir.OSWITCH:
160 n := n.(*ir.SwitchStmt)
161 walkSwitch(n)
162 return n
163
164 case ir.ORANGE:
165 n := n.(*ir.RangeStmt)
166 return walkRange(n)
167 }
168
169
170
171
172 }
173
174 func walkStmtList(s []ir.Node) {
175 for i := range s {
176 s[i] = walkStmt(s[i])
177 }
178 }
179
180
181 func walkFor(n *ir.ForStmt) ir.Node {
182 if n.Cond != nil {
183 init := ir.TakeInit(n.Cond)
184 walkStmtList(init)
185 n.Cond = walkExpr(n.Cond, &init)
186 n.Cond = ir.InitExpr(init, n.Cond)
187 }
188
189 n.Post = walkStmt(n.Post)
190 walkStmtList(n.Body)
191 return n
192 }
193
194
195
196
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
201 }
202 return false
203 }
204
205
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)
209 }
210
211 var init ir.Nodes
212
213 call := n.Call.(*ir.CallExpr)
214 call.Fun = walkExpr(call.Fun, &init)
215
216 if len(init) > 0 {
217 init.Append(n)
218 return ir.NewBlockStmt(n.Pos(), init)
219 }
220 return n
221 }
222
223
224 func walkIf(n *ir.IfStmt) ir.Node {
225 n.Cond = walkExpr(n.Cond, n.PtrInit())
226 walkStmtList(n.Body)
227 walkStmtList(n.Else)
228 return n
229 }
230
View as plain text