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