]> Cypherpunks.ru repositories - gostls13.git/blob - test/inline.go
cmd/compile: reenable inline static init
[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
199 func inlineRangeIntoMe(data []int) { // ERROR "can inline inlineRangeIntoMe" "data does not escape"
200         rangeFunc(data, 12) // ERROR "inlining call to rangeFunc"
201 }
202
203 func rangeFunc(xs []int, b int) int { // ERROR "can inline rangeFunc" "xs does not escape"
204         for i, x := range xs {
205                 if x == b {
206                         return i
207                 }
208         }
209         return -1
210 }
211
212 type T struct{}
213
214 func (T) meth(int, int) {} // ERROR "can inline T.meth"
215
216 func k() (T, int, int) { return T{}, 0, 0 } // ERROR "can inline k"
217
218 func f3() { // ERROR "can inline f3"
219         T.meth(k()) // ERROR "inlining call to k" "inlining call to T.meth"
220         // ERRORAUTO "inlining call to T.meth"
221 }
222
223 func small1() { // ERROR "can inline small1"
224         runtime.GC()
225 }
226 func small2() int { // ERROR "can inline small2"
227         return runtime.GOMAXPROCS(0)
228 }
229 func small3(t T) { // ERROR "can inline small3"
230         t.meth2(3, 5)
231 }
232 func small4(t T) { // not inlineable - has 2 calls.
233         t.meth2(runtime.GOMAXPROCS(0), 5)
234 }
235 func (T) meth2(int, int) { // not inlineable - has 2 calls.
236         runtime.GC()
237         runtime.GC()
238 }
239
240 // Issue #29737 - make sure we can do inlining for a chain of recursive functions
241 func ee() { // ERROR "can inline ee"
242         ff(100) // ERROR "inlining call to ff" "inlining call to gg" "inlining call to hh"
243 }
244
245 func ff(x int) { // ERROR "can inline ff"
246         if x < 0 {
247                 return
248         }
249         gg(x - 1) // ERROR "inlining call to gg" "inlining call to hh"
250 }
251 func gg(x int) { // ERROR "can inline gg"
252         hh(x - 1) // ERROR "inlining call to hh" "inlining call to ff"
253 }
254 func hh(x int) { // ERROR "can inline hh"
255         ff(x - 1) // ERROR "inlining call to ff" "inlining call to gg"
256 }
257
258 // Issue #14768 - make sure we can inline for loops.
259 func for1(fn func() bool) { // ERROR "can inline for1" "fn does not escape"
260         for {
261                 if fn() {
262                         break
263                 } else {
264                         continue
265                 }
266         }
267 }
268
269 func for2(fn func() bool) { // ERROR "can inline for2" "fn does not escape"
270 Loop:
271         for {
272                 if fn() {
273                         break Loop
274                 } else {
275                         continue Loop
276                 }
277         }
278 }
279
280 // Issue #18493 - make sure we can do inlining of functions with a method value
281 type T1 struct{}
282
283 func (a T1) meth(val int) int { // ERROR "can inline T1.meth"
284         return val + 5
285 }
286
287 func getMeth(t1 T1) func(int) int { // ERROR "can inline getMeth"
288         return t1.meth // ERROR "t1.meth escapes to heap"
289         // ERRORAUTO "inlining call to T1.meth"
290 }
291
292 func ii() { // ERROR "can inline ii"
293         var t1 T1
294         f := getMeth(t1) // ERROR "inlining call to getMeth" "t1.meth does not escape"
295         _ = f(3)
296 }
297
298 // Issue #42194 - make sure that functions evaluated in
299 // go and defer statements can be inlined.
300 func gd1(int) {
301         defer gd1(gd2()) // ERROR "inlining call to gd2"
302         defer gd3()()    // ERROR "inlining call to gd3"
303         go gd1(gd2())    // ERROR "inlining call to gd2"
304         go gd3()()       // ERROR "inlining call to gd3"
305 }
306
307 func gd2() int { // ERROR "can inline gd2"
308         return 1
309 }
310
311 func gd3() func() { // ERROR "can inline gd3"
312         return ii
313 }
314
315 // Issue #42788 - ensure ODEREF OCONVNOP* OADDR is low cost.
316 func EncodeQuad(d []uint32, x [6]float32) { // ERROR "can inline EncodeQuad" "d does not escape"
317         _ = d[:6]
318         d[0] = float32bits(x[0]) // ERROR "inlining call to float32bits"
319         d[1] = float32bits(x[1]) // ERROR "inlining call to float32bits"
320         d[2] = float32bits(x[2]) // ERROR "inlining call to float32bits"
321         d[3] = float32bits(x[3]) // ERROR "inlining call to float32bits"
322         d[4] = float32bits(x[4]) // ERROR "inlining call to float32bits"
323         d[5] = float32bits(x[5]) // ERROR "inlining call to float32bits"
324 }
325
326 // float32bits is a copy of math.Float32bits to ensure that
327 // these tests pass with `-gcflags=-l`.
328 func float32bits(f float32) uint32 { // ERROR "can inline float32bits"
329         return *(*uint32)(unsafe.Pointer(&f))
330 }
331
332 // Ensure OCONVNOP is zero cost.
333 func Conv(v uint64) uint64 { // ERROR "can inline Conv"
334         return conv2(conv2(conv2(v))) // ERROR "inlining call to (conv1|conv2)"
335 }
336 func conv2(v uint64) uint64 { // ERROR "can inline conv2"
337         return conv1(conv1(conv1(conv1(v)))) // ERROR "inlining call to conv1"
338 }
339 func conv1(v uint64) uint64 { // ERROR "can inline conv1"
340         return uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(v)))))))))))
341 }
342
343 func select1(x, y chan bool) int { // ERROR "can inline select1" "x does not escape" "y does not escape"
344         select {
345         case <-x:
346                 return 1
347         case <-y:
348                 return 2
349         }
350 }
351
352 func select2(x, y chan bool) { // ERROR "can inline select2" "x does not escape" "y does not escape"
353 loop: // test that labeled select can be inlined.
354         select {
355         case <-x:
356                 break loop
357         case <-y:
358         }
359 }
360
361 func inlineSelect2(x, y chan bool) { // ERROR "can inline inlineSelect2" ERROR "x does not escape" "y does not escape"
362 loop:
363         for i := 0; i < 5; i++ {
364                 if i == 3 {
365                         break loop
366                 }
367                 select2(x, y) // ERROR "inlining call to select2"
368         }
369 }