github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/walk/stmt.go (about) 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. 4 5 package walk 6 7 import ( 8 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 9 "github.com/bir3/gocompiler/src/cmd/compile/internal/ir" 10 ) 11 12 // The result of walkStmt MUST be assigned back to n, e.g. 13 // 14 // n.Left = walkStmt(n.Left) 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.OCLOSE, 43 ir.OCOPY, 44 ir.OCALLINTER, 45 ir.OCALL, 46 ir.OCALLFUNC, 47 ir.ODELETE, 48 ir.OSEND, 49 ir.OPRINT, 50 ir.OPRINTN, 51 ir.OPANIC, 52 ir.ORECOVERFP, 53 ir.OGETG: 54 if n.Typecheck() == 0 { 55 base.Fatalf("missing typecheck: %+v", n) 56 } 57 init := ir.TakeInit(n) 58 n = walkExpr(n, &init) 59 if n.Op() == ir.ONAME { 60 // copy rewrote to a statement list and a temp for the length. 61 // Throw away the temp to avoid plain values as statements. 62 n = ir.NewBlockStmt(n.Pos(), init) 63 init = nil 64 } 65 if len(init) > 0 { 66 switch n.Op() { 67 case ir.OAS, ir.OAS2, ir.OBLOCK: 68 n.(ir.InitNode).PtrInit().Prepend(init...) 69 70 default: 71 init.Append(n) 72 n = ir.NewBlockStmt(n.Pos(), init) 73 } 74 } 75 return n 76 77 // special case for a receive where we throw away 78 // the value received. 79 case ir.ORECV: 80 n := n.(*ir.UnaryExpr) 81 return walkRecv(n) 82 83 case ir.OBREAK, 84 ir.OCONTINUE, 85 ir.OFALL, 86 ir.OGOTO, 87 ir.OLABEL, 88 ir.OJUMPTABLE, 89 ir.ODCL, 90 ir.ODCLCONST, 91 ir.ODCLTYPE, 92 ir.OCHECKNIL: 93 return n 94 95 case ir.OBLOCK: 96 n := n.(*ir.BlockStmt) 97 walkStmtList(n.List) 98 return n 99 100 case ir.OCASE: 101 base.Errorf("case statement out of place") 102 panic("unreachable") 103 104 case ir.ODEFER: 105 n := n.(*ir.GoDeferStmt) 106 ir.CurFunc.SetHasDefer(true) 107 ir.CurFunc.NumDefers++ 108 if ir.CurFunc.NumDefers > maxOpenDefers { 109 // Don't allow open-coded defers if there are more than 110 // 8 defers in the function, since we use a single 111 // byte to record active defers. 112 ir.CurFunc.SetOpenCodedDeferDisallowed(true) 113 } 114 if n.Esc() != ir.EscNever { 115 // If n.Esc is not EscNever, then this defer occurs in a loop, 116 // so open-coded defers cannot be used in this function. 117 ir.CurFunc.SetOpenCodedDeferDisallowed(true) 118 } 119 fallthrough 120 case ir.OGO: 121 n := n.(*ir.GoDeferStmt) 122 return walkGoDefer(n) 123 124 case ir.OFOR: 125 n := n.(*ir.ForStmt) 126 return walkFor(n) 127 128 case ir.OIF: 129 n := n.(*ir.IfStmt) 130 return walkIf(n) 131 132 case ir.ORETURN: 133 n := n.(*ir.ReturnStmt) 134 return walkReturn(n) 135 136 case ir.OTAILCALL: 137 n := n.(*ir.TailCallStmt) 138 139 var init ir.Nodes 140 n.Call.X = walkExpr(n.Call.X, &init) 141 142 if len(init) > 0 { 143 init.Append(n) 144 return ir.NewBlockStmt(n.Pos(), init) 145 } 146 return n 147 148 case ir.OINLMARK: 149 n := n.(*ir.InlineMarkStmt) 150 return n 151 152 case ir.OSELECT: 153 n := n.(*ir.SelectStmt) 154 walkSelect(n) 155 return n 156 157 case ir.OSWITCH: 158 n := n.(*ir.SwitchStmt) 159 walkSwitch(n) 160 return n 161 162 case ir.ORANGE: 163 n := n.(*ir.RangeStmt) 164 return walkRange(n) 165 } 166 167 // No return! Each case must return (or panic), 168 // to avoid confusion about what gets returned 169 // in the presence of type assertions. 170 } 171 172 func walkStmtList(s []ir.Node) { 173 for i := range s { 174 s[i] = walkStmt(s[i]) 175 } 176 } 177 178 // walkFor walks an OFOR node. 179 func walkFor(n *ir.ForStmt) ir.Node { 180 if n.Cond != nil { 181 init := ir.TakeInit(n.Cond) 182 walkStmtList(init) 183 n.Cond = walkExpr(n.Cond, &init) 184 n.Cond = ir.InitExpr(init, n.Cond) 185 } 186 187 n.Post = walkStmt(n.Post) 188 walkStmtList(n.Body) 189 return n 190 } 191 192 // validGoDeferCall reports whether call is a valid call to appear in 193 // a go or defer statement; that is, whether it's a regular function 194 // call without arguments or results. 195 func validGoDeferCall(call ir.Node) bool { 196 if call, ok := call.(*ir.CallExpr); ok && call.Op() == ir.OCALLFUNC && len(call.KeepAlive) == 0 { 197 sig := call.X.Type() 198 return sig.NumParams()+sig.NumResults() == 0 199 } 200 return false 201 } 202 203 // walkGoDefer walks an OGO or ODEFER node. 204 func walkGoDefer(n *ir.GoDeferStmt) ir.Node { 205 if !validGoDeferCall(n.Call) { 206 base.FatalfAt(n.Pos(), "invalid %v call: %v", n.Op(), n.Call) 207 } 208 209 var init ir.Nodes 210 211 call := n.Call.(*ir.CallExpr) 212 call.X = walkExpr(call.X, &init) 213 214 if len(init) > 0 { 215 init.Append(n) 216 return ir.NewBlockStmt(n.Pos(), init) 217 } 218 return n 219 } 220 221 // walkIf walks an OIF node. 222 func walkIf(n *ir.IfStmt) ir.Node { 223 n.Cond = walkExpr(n.Cond, n.PtrInit()) 224 walkStmtList(n.Body) 225 walkStmtList(n.Else) 226 return n 227 }