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