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