]> Cypherpunks.ru repositories - gostls13.git/blob - test/inline.go
cmd/compile: allow inlining labeled for-statement and switch-statement
[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 "func literal does not escape" "can inline o.func2"
96                 }
97         }(11) // ERROR "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 r(z int) int {
111         foo := func(x int) int { // ERROR "can inline r.func1" "func literal does not escape"
112                 return x + z
113         }
114         bar := func(x int) int { // ERROR "func literal does not escape" "can inline r.func2"
115                 return x + func(y int) int { // ERROR "can inline r.func2.1" "can inline r.func3"
116                         return 2*y + x*z
117                 }(x) // ERROR "inlining call to r.func2.1"
118         }
119         return foo(42) + bar(42) // ERROR "inlining call to r.func1" "inlining call to r.func2" "inlining call to r.func3"
120 }
121
122 func s0(x int) int { // ERROR "can inline s0"
123         foo := func() { // ERROR "can inline s0.func1" "func literal does not escape"
124                 x = x + 1
125         }
126         foo() // ERROR "inlining call to s0.func1"
127         return x
128 }
129
130 func s1(x int) int { // ERROR "can inline s1"
131         foo := func() int { // ERROR "can inline s1.func1" "func literal does not escape"
132                 return x
133         }
134         x = x + 1
135         return foo() // ERROR "inlining call to s1.func1"
136 }
137
138 func switchBreak(x, y int) int { // ERROR "can inline switchBreak"
139         var n int
140         switch x {
141         case 0:
142                 n = 1
143         Done:
144                 switch y {
145                 case 0:
146                         n += 10
147                         break Done
148                 }
149                 n = 2
150         }
151         return n
152 }
153
154 func switchType(x interface{}) int { // ERROR "can inline switchType" "x does not escape"
155         switch x.(type) {
156         case int:
157                 return x.(int)
158         default:
159                 return 0
160         }
161 }
162
163 type T struct{}
164
165 func (T) meth(int, int) {} // ERROR "can inline T.meth"
166
167 func k() (T, int, int) { return T{}, 0, 0 } // ERROR "can inline k"
168
169 func f3() { // ERROR "can inline f3"
170         T.meth(k()) // ERROR "inlining call to k" "inlining call to T.meth"
171         // ERRORAUTO "inlining call to T.meth"
172 }
173
174 func small1() { // ERROR "can inline small1"
175         runtime.GC()
176 }
177 func small2() int { // ERROR "can inline small2"
178         return runtime.GOMAXPROCS(0)
179 }
180 func small3(t T) { // ERROR "can inline small3"
181         t.meth2(3, 5)
182 }
183 func small4(t T) { // not inlineable - has 2 calls.
184         t.meth2(runtime.GOMAXPROCS(0), 5)
185 }
186 func (T) meth2(int, int) { // not inlineable - has 2 calls.
187         runtime.GC()
188         runtime.GC()
189 }
190
191 // Issue #29737 - make sure we can do inlining for a chain of recursive functions
192 func ee() { // ERROR "can inline ee"
193         ff(100) // ERROR "inlining call to ff" "inlining call to gg" "inlining call to hh"
194 }
195
196 func ff(x int) { // ERROR "can inline ff"
197         if x < 0 {
198                 return
199         }
200         gg(x - 1)
201 }
202 func gg(x int) { // ERROR "can inline gg"
203         hh(x - 1)
204 }
205 func hh(x int) { // ERROR "can inline hh"
206         ff(x - 1) // ERROR "inlining call to ff"  // ERROR "inlining call to gg"
207 }
208
209 // Issue #14768 - make sure we can inline for loops.
210 func for1(fn func() bool) { // ERROR "can inline for1" "fn does not escape"
211         for {
212                 if fn() {
213                         break
214                 } else {
215                         continue
216                 }
217         }
218 }
219
220 func for2(fn func() bool) { // ERROR "can inline for2" "fn does not escape"
221 Loop:
222         for {
223                 if fn() {
224                         break Loop
225                 } else {
226                         continue Loop
227                 }
228         }
229 }
230
231 // Issue #18493 - make sure we can do inlining of functions with a method value
232 type T1 struct{}
233
234 func (a T1) meth(val int) int { // ERROR "can inline T1.meth"
235         return val + 5
236 }
237
238 func getMeth(t1 T1) func(int) int { // ERROR "can inline getMeth"
239         return t1.meth // ERROR "t1.meth escapes to heap"
240         // ERRORAUTO "inlining call to T1.meth"
241 }
242
243 func ii() { // ERROR "can inline ii"
244         var t1 T1
245         f := getMeth(t1) // ERROR "inlining call to getMeth" "t1.meth does not escape"
246         _ = f(3)
247 }
248
249 // Issue #42194 - make sure that functions evaluated in
250 // go and defer statements can be inlined.
251 func gd1(int) {
252         defer gd1(gd2()) // ERROR "inlining call to gd2"
253         defer gd3()()    // ERROR "inlining call to gd3"
254         go gd1(gd2())    // ERROR "inlining call to gd2"
255         go gd3()()       // ERROR "inlining call to gd3"
256 }
257
258 func gd2() int { // ERROR "can inline gd2"
259         return 1
260 }
261
262 func gd3() func() { // ERROR "can inline gd3"
263         return ii
264 }
265
266 // Issue #42788 - ensure ODEREF OCONVNOP* OADDR is low cost.
267 func EncodeQuad(d []uint32, x [6]float32) { // ERROR "can inline EncodeQuad" "d does not escape"
268         _ = d[:6]
269         d[0] = float32bits(x[0]) // ERROR "inlining call to float32bits"
270         d[1] = float32bits(x[1]) // ERROR "inlining call to float32bits"
271         d[2] = float32bits(x[2]) // ERROR "inlining call to float32bits"
272         d[3] = float32bits(x[3]) // ERROR "inlining call to float32bits"
273         d[4] = float32bits(x[4]) // ERROR "inlining call to float32bits"
274         d[5] = float32bits(x[5]) // ERROR "inlining call to float32bits"
275 }
276
277 // float32bits is a copy of math.Float32bits to ensure that
278 // these tests pass with `-gcflags=-l`.
279 func float32bits(f float32) uint32 { // ERROR "can inline float32bits"
280         return *(*uint32)(unsafe.Pointer(&f))
281 }
282
283 // Ensure OCONVNOP is zero cost.
284 func Conv(v uint64) uint64 { // ERROR "can inline Conv"
285         return conv2(conv2(conv2(v))) // ERROR "inlining call to (conv1|conv2)"
286 }
287 func conv2(v uint64) uint64 { // ERROR "can inline conv2"
288         return conv1(conv1(conv1(conv1(v)))) // ERROR "inlining call to conv1"
289 }
290 func conv1(v uint64) uint64 { // ERROR "can inline conv1"
291         return uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(uint64(v)))))))))))
292 }