]> Cypherpunks.ru repositories - gostls13.git/blob - test/inline.go
cmd/compile: don't emit inltree for closure within body of inlined func
[gostls13.git] / test / inline.go
1 // errorcheck -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 _() int { // ERROR "can inline _"
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 // can't currently inline functions with a break statement
139 func switchBreak(x, y int) int {
140         var n int
141         switch x {
142         case 0:
143                 n = 1
144         Done:
145                 switch y {
146                 case 0:
147                         n += 10
148                         break Done
149                 }
150                 n = 2
151         }
152         return n
153 }
154
155 func switchType(x interface{}) int { // ERROR "can inline switchType" "x does not escape"
156         switch x.(type) {
157         case int:
158                 return x.(int)
159         default:
160                 return 0
161         }
162 }
163
164 type T struct{}
165
166 func (T) meth(int, int) {} // ERROR "can inline T.meth"
167
168 func k() (T, int, int) { return T{}, 0, 0 } // ERROR "can inline k"
169
170 func _() { // ERROR "can inline _"
171         T.meth(k()) // ERROR "inlining call to k" "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 // BAD: for2 should be inlineable too.
221 func for2(fn func() bool) { // ERROR "fn does not escape"
222 Loop:
223         for {
224                 if fn() {
225                         break Loop
226                 } else {
227                         continue Loop
228                 }
229         }
230 }
231
232 // Issue #18493 - make sure we can do inlining of functions with a method value
233 type T1 struct{}
234
235 func (a T1) meth(val int) int { // ERROR "can inline T1.meth" "inlining call to T1.meth"
236         return val + 5
237 }
238
239 func getMeth(t1 T1) func(int) int { // ERROR "can inline getMeth"
240         return t1.meth // ERROR "t1.meth escapes to heap"
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 }