github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/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/go-asm/go/cmd/compile/base" 9 "github.com/go-asm/go/cmd/compile/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.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 // 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) 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 // special case for a receive where we throw away 80 // the value received. 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 // 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) 115 } 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) 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 // No return! Each case must return (or panic), 170 // to avoid confusion about what gets returned 171 // in the presence of type assertions. 172 } 173 174 func walkStmtList(s []ir.Node) { 175 for i := range s { 176 s[i] = walkStmt(s[i]) 177 } 178 } 179 180 // walkFor walks an OFOR node. 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 // 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 201 } 202 return false 203 } 204 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) 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 // walkIf walks an OIF node. 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 }