1// errorcheckwithauto -0 -m -d=inlfuncswithclosures=1 2 3//go:build goexperiment.newinliner 4 5// Copyright 2023 The Go Authors. All rights reserved. 6// Use of this source code is governed by a BSD-style 7// license that can be found in the LICENSE file. 8 9// Test, using compiler diagnostic flags, that inlining is working. 10// Compiles but does not run. 11 12package foo 13 14import ( 15 "errors" 16 "runtime" 17 "unsafe" 18) 19 20func add2(p *byte, n uintptr) *byte { // ERROR "can inline add2" "leaking param: p to result" 21 return (*byte)(add1(unsafe.Pointer(p), n)) // ERROR "inlining call to add1" 22} 23 24func add1(p unsafe.Pointer, x uintptr) unsafe.Pointer { // ERROR "can inline add1" "leaking param: p to result" 25 return unsafe.Pointer(uintptr(p) + x) 26} 27 28func f(x *byte) *byte { // ERROR "can inline f" "leaking param: x to result" 29 return add2(x, 1) // ERROR "inlining call to add2" "inlining call to add1" 30} 31 32//go:noinline 33func g(x int) int { 34 return x + 1 35} 36 37func h(x int) int { // ERROR "can inline h" 38 return x + 2 39} 40 41func i(x int) int { // ERROR "can inline i" 42 const y = 2 43 return x + y 44} 45 46func j(x int) int { // ERROR "can inline j" 47 switch { 48 case x > 0: 49 return x + 2 50 default: 51 return x + 1 52 } 53} 54 55func f2() int { // ERROR "can inline f2" 56 tmp1 := h 57 tmp2 := tmp1 58 return tmp2(0) // ERROR "inlining call to h" 59} 60 61var abc = errors.New("abc") // ERROR "inlining call to errors.New" 62 63var somethingWrong error 64 65// local closures can be inlined 66func l(x, y int) (int, int, error) { // ERROR "can inline l" 67 e := func(err error) (int, int, error) { // ERROR "can inline l.func1" "func literal does not escape" "leaking param: err to result" 68 return 0, 0, err 69 } 70 if x == y { 71 e(somethingWrong) // ERROR "inlining call to l.func1" 72 } else { 73 f := e 74 f(nil) // ERROR "inlining call to l.func1" 75 } 76 return y, x, nil 77} 78 79// any re-assignment prevents closure inlining 80func m() int { 81 foo := func() int { return 1 } // ERROR "can inline m.func1" "func literal does not escape" 82 x := foo() 83 foo = func() int { return 2 } // ERROR "can inline m.func2" "func literal does not escape" 84 return x + foo() 85} 86 87// address taking prevents closure inlining 88func n() int { // ERROR "can inline n" 89 foo := func() int { return 1 } // ERROR "can inline n.func1" "func literal does not escape" 90 bar := &foo 91 x := (*bar)() + foo() 92 return x 93} 94 95// make sure assignment inside closure is detected 96func o() int { // ERROR "can inline o" 97 foo := func() int { return 1 } // ERROR "can inline o.func1" "func literal does not escape" 98 func(x int) { // ERROR "can inline o.func2" 99 if x > 10 { 100 foo = func() int { return 2 } // ERROR "can inline o.func2" 101 } 102 }(11) // ERROR "func literal does not escape" "inlining call to o.func2" 103 return foo() 104} 105 106func p() int { // ERROR "can inline p" 107 return func() int { return 42 }() // ERROR "can inline p.func1" "inlining call to p.func1" 108} 109 110func q(x int) int { // ERROR "can inline q" 111 foo := func() int { return x * 2 } // ERROR "can inline q.func1" "func literal does not escape" 112 return foo() // ERROR "inlining call to q.func1" 113} 114 115func r(z int) int { // ERROR "can inline r" 116 foo := func(x int) int { // ERROR "can inline r.func1" "func literal does not escape" 117 return x + z 118 } 119 bar := func(x int) int { // ERROR "func literal does not escape" "can inline r.func2" 120 return x + func(y int) int { // ERROR "can inline r.func2.1" "can inline r.r.func2.func3" 121 return 2*y + x*z 122 }(x) // ERROR "inlining call to r.func2.1" 123 } 124 return foo(42) + bar(42) // ERROR "inlining call to r.func1" "inlining call to r.func2" "inlining call to r.r.func2.func3" 125} 126 127func s0(x int) int { // ERROR "can inline s0" 128 foo := func() { // ERROR "can inline s0.func1" "func literal does not escape" 129 x = x + 1 130 } 131 foo() // ERROR "inlining call to s0.func1" 132 return x 133} 134 135func s1(x int) int { // ERROR "can inline s1" 136 foo := func() int { // ERROR "can inline s1.func1" "func literal does not escape" 137 return x 138 } 139 x = x + 1 140 return foo() // ERROR "inlining call to s1.func1" 141} 142 143func switchBreak(x, y int) int { // ERROR "can inline switchBreak" 144 var n int 145 switch x { 146 case 0: 147 n = 1 148 Done: 149 switch y { 150 case 0: 151 n += 10 152 break Done 153 } 154 n = 2 155 } 156 return n 157} 158 159func switchType(x interface{}) int { // ERROR "can inline switchType" "x does not escape" 160 switch x.(type) { 161 case int: 162 return x.(int) 163 default: 164 return 0 165 } 166} 167 168// Test that switches on constant things, with constant cases, only cost anything for 169// the case that matches. See issue 50253. 170func switchConst1(p func(string)) { // ERROR "can inline switchConst" "p does not escape" 171 const c = 1 172 switch c { 173 case 0: 174 p("zero") 175 case 1: 176 p("one") 177 case 2: 178 p("two") 179 default: 180 p("other") 181 } 182} 183 184func switchConst2() string { // ERROR "can inline switchConst2" 185 switch runtime.GOOS { 186 case "linux": 187 return "Leenooks" 188 case "windows": 189 return "Windoze" 190 case "darwin": 191 return "MackBone" 192 case "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100": 193 return "Numbers" 194 default: 195 return "oh nose!" 196 } 197} 198func switchConst3() string { // ERROR "can inline switchConst3" 199 switch runtime.GOOS { 200 case "Linux": 201 panic("Linux") 202 case "Windows": 203 panic("Windows") 204 case "Darwin": 205 panic("Darwin") 206 case "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100": 207 panic("Numbers") 208 default: 209 return "oh nose!" 210 } 211} 212func switchConst4() { // ERROR "can inline switchConst4" 213 const intSize = 32 << (^uint(0) >> 63) 214 want := func() string { // ERROR "can inline switchConst4.func1" 215 switch intSize { 216 case 32: 217 return "32" 218 case 64: 219 return "64" 220 default: 221 panic("unreachable") 222 } 223 }() // ERROR "inlining call to switchConst4.func1" 224 _ = want 225} 226 227func inlineRangeIntoMe(data []int) { // ERROR "can inline inlineRangeIntoMe" "data does not escape" 228 rangeFunc(data, 12) // ERROR "inlining call to rangeFunc" 229} 230 231func rangeFunc(xs []int, b int) int { // ERROR "can inline rangeFunc" "xs does not escape" 232 for i, x := range xs { 233 if x == b { 234 return i 235 } 236 } 237 return -1 238} 239 240type T struct{} 241 242func (T) meth(int, int) {} // ERROR "can inline T.meth" 243 244func k() (T, int, int) { return T{}, 0, 0 } // ERROR "can inline k" 245 246func f3() { // ERROR "can inline f3" 247 T.meth(k()) // ERROR "inlining call to k" "inlining call to T.meth" 248 // ERRORAUTO "inlining call to T.meth" 249} 250 251func small1() { // ERROR "can inline small1" 252 runtime.GC() 253} 254func small2() int { // ERROR "can inline small2" 255 return runtime.GOMAXPROCS(0) 256} 257func small3(t T) { // ERROR "can inline small3" 258 t.meth2(3, 5) 259} 260func small4(t T) { // ERROR "can inline small4" 261 t.meth2(runtime.GOMAXPROCS(0), 5) 262} 263func (T) meth2(int, int) { // ERROR "can inline T.meth2" 264 runtime.GC() 265 runtime.GC() 266} 267 268// Issue #29737 - make sure we can do inlining for a chain of recursive functions 269func ee() { // ERROR "can inline ee" 270 ff(100) // ERROR "inlining call to ff" "inlining call to gg" "inlining call to hh" 271} 272 273func ff(x int) { // ERROR "can inline ff" 274 if x < 0 { 275 return 276 } 277 gg(x - 1) // ERROR "inlining call to gg" "inlining call to hh" 278} 279func gg(x int) { // ERROR "can inline gg" 280 hh(x - 1) // ERROR "inlining call to hh" "inlining call to ff" 281} 282func hh(x int) { // ERROR "can inline hh" 283 ff(x - 1) // ERROR "inlining call to ff" "inlining call to gg" 284} 285 286// Issue #14768 - make sure we can inline for loops. 287func for1(fn func() bool) { // ERROR "can inline for1" "fn does not escape" 288 for { 289 if fn() { 290 break 291 } else { 292 continue 293 } 294 } 295} 296 297func for2(fn func() bool) { // ERROR "can inline for2" "fn does not escape" 298Loop: 299 for { 300 if fn() { 301 break Loop 302 } else { 303 continue Loop 304 } 305 } 306} 307 308// Issue #18493 - make sure we can do inlining of functions with a method value 309type T1 struct{} 310 311func (a T1) meth(val int) int { // ERROR "can inline T1.meth" 312 return val + 5 313} 314 315func getMeth(t1 T1) func(int) int { // ERROR "can inline getMeth" 316 return t1.meth // ERROR "t1.meth escapes to heap" 317 // ERRORAUTO "inlining call to T1.meth" 318} 319 320func ii() { // ERROR "can inline ii" 321 var t1 T1 322 f := getMeth(t1) // ERROR "inlining call to getMeth" "t1.meth does not escape" 323 _ = f(3) 324} 325 326// Issue #42194 - make sure that functions evaluated in 327// go and defer statements can be inlined. 328func gd1(int) { 329 defer gd1(gd2()) // ERROR "inlining call to gd2" "can inline gd1.deferwrap1" 330 defer gd3()() // ERROR "inlining call to gd3" 331 go gd1(gd2()) // ERROR "inlining call to gd2" "can inline gd1.gowrap2" 332 go gd3()() // ERROR "inlining call to gd3" 333} 334 335func gd2() int { // ERROR "can inline gd2" 336 return 1 337} 338 339func gd3() func() { // ERROR "can inline gd3" 340 return ii 341} 342 343// Issue #42788 - ensure ODEREF OCONVNOP* OADDR is low cost. 344func EncodeQuad(d []uint32, x [6]float32) { // ERROR "can inline EncodeQuad" "d does not escape" 345 _ = d[:6] 346 d[0] = float32bits(x[0]) // ERROR "inlining call to float32bits" 347 d[1] = float32bits(x[1]) // ERROR "inlining call to float32bits" 348 d[2] = float32bits(x[2]) // ERROR "inlining call to float32bits" 349 d[3] = float32bits(x[3]) // ERROR "inlining call to float32bits" 350 d[4] = float32bits(x[4]) // ERROR "inlining call to float32bits" 351 d[5] = float32bits(x[5]) // ERROR "inlining call to float32bits" 352} 353 354// float32bits is a copy of math.Float32bits to ensure that 355// these tests pass with `-gcflags=-l`. 356func float32bits(f float32) uint32 { // ERROR "can inline float32bits" 357 return *(*uint32)(unsafe.Pointer(&f)) 358} 359 360// Ensure OCONVNOP is zero cost. 361func Conv(v uint64) uint64 { // ERROR "can inline Conv" 362 return conv2(conv2(conv2(v))) // ERROR "inlining call to (conv1|conv2)" 363} 364func conv2(v uint64) uint64 { // ERROR "can inline conv2" 365 return conv1(conv1(conv1(conv1(v)))) // ERROR "inlining call to conv1" 366} 367func conv1(v uint64) uint64 { // ERROR "can inline conv1" 368 return uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(v))))))))))) 369} 370 371func select1(x, y chan bool) int { // ERROR "can inline select1" "x does not escape" "y does not escape" 372 select { 373 case <-x: 374 return 1 375 case <-y: 376 return 2 377 } 378} 379 380func select2(x, y chan bool) { // ERROR "can inline select2" "x does not escape" "y does not escape" 381loop: // test that labeled select can be inlined. 382 select { 383 case <-x: 384 break loop 385 case <-y: 386 } 387} 388 389func inlineSelect2(x, y chan bool) { // ERROR "can inline inlineSelect2" ERROR "x does not escape" "y does not escape" 390loop: 391 for i := 0; i < 5; i++ { 392 if i == 3 { 393 break loop 394 } 395 select2(x, y) // ERROR "inlining call to select2" 396 } 397} 398