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