1// errorcheck -0 -m -l
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 escape analysis through ... parameters.
8
9package foo
10
11func FooN(vals ...*int) (s int) { // ERROR "vals does not escape"
12	for _, v := range vals {
13		s += *v
14	}
15	return s
16}
17
18// Append forces heap allocation and copies entries in vals to heap, therefore they escape to heap.
19func FooNx(x *int, vals ...*int) (s int) { // ERROR "leaking param: x" "leaking param content: vals"
20	vals = append(vals, x)
21	return FooN(vals...)
22}
23
24var sink []*int
25
26func FooNy(x *int, vals ...*int) (s int) { // ERROR "leaking param: x" "leaking param: vals"
27	vals = append(vals, x)
28	sink = vals
29	return FooN(vals...)
30}
31
32func FooNz(vals ...*int) (s int) { // ERROR "leaking param: vals"
33	sink = vals
34	return FooN(vals...)
35}
36
37func TFooN() {
38	for i := 0; i < 1000; i++ {
39		var i, j int
40		FooN(&i, &j) // ERROR "... argument does not escape"
41	}
42}
43
44func TFooNx() {
45	for i := 0; i < 1000; i++ {
46		var i, j, k int   // ERROR "moved to heap: i" "moved to heap: j" "moved to heap: k"
47		FooNx(&k, &i, &j) // ERROR "... argument does not escape"
48	}
49}
50
51func TFooNy() {
52	for i := 0; i < 1000; i++ {
53		var i, j, k int   // ERROR "moved to heap: i" "moved to heap: j" "moved to heap: k"
54		FooNy(&k, &i, &j) // ERROR "... argument escapes to heap"
55	}
56}
57
58func TFooNz() {
59	for i := 0; i < 1000; i++ {
60		var i, j int  // ERROR "moved to heap: i" "moved to heap: j"
61		FooNz(&i, &j) // ERROR "... argument escapes to heap"
62	}
63}
64
65var isink *int32
66
67func FooI(args ...interface{}) { // ERROR "leaking param content: args"
68	for i := 0; i < len(args); i++ {
69		switch x := args[i].(type) {
70		case nil:
71			println("is nil")
72		case int32:
73			println("is int32")
74		case *int32:
75			println("is *int32")
76			isink = x
77		case string:
78			println("is string")
79		}
80	}
81}
82
83func TFooI() {
84	a := int32(1) // ERROR "moved to heap: a"
85	b := "cat"
86	c := &a
87	FooI(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "... argument does not escape"
88}
89
90func FooJ(args ...interface{}) *int32 { // ERROR "leaking param: args to result ~r0 level=1"
91	for i := 0; i < len(args); i++ {
92		switch x := args[i].(type) {
93		case nil:
94			println("is nil")
95		case int32:
96			println("is int32")
97		case *int32:
98			println("is *int32")
99			return x
100		case string:
101			println("is string")
102		}
103	}
104	return nil
105}
106
107func TFooJ1() {
108	a := int32(1)
109	b := "cat"
110	c := &a
111	FooJ(a, b, c) // ERROR "a does not escape" "b does not escape" "... argument does not escape"
112}
113
114func TFooJ2() {
115	a := int32(1) // ERROR "moved to heap: a"
116	b := "cat"
117	c := &a
118	isink = FooJ(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "... argument does not escape"
119}
120
121type fakeSlice struct {
122	l int
123	a *[4]interface{}
124}
125
126func FooK(args fakeSlice) *int32 { // ERROR "leaking param: args to result ~r0 level=1"
127	for i := 0; i < args.l; i++ {
128		switch x := (*args.a)[i].(type) {
129		case nil:
130			println("is nil")
131		case int32:
132			println("is int32")
133		case *int32:
134			println("is *int32")
135			return x
136		case string:
137			println("is string")
138		}
139	}
140	return nil
141}
142
143func TFooK2() {
144	a := int32(1) // ERROR "moved to heap: a"
145	b := "cat"
146	c := &a
147	fs := fakeSlice{3, &[4]interface{}{a, b, c, nil}} // ERROR "a escapes to heap" "b escapes to heap" "&\[4\]interface {}{...} does not escape"
148	isink = FooK(fs)
149}
150
151func FooL(args []interface{}) *int32 { // ERROR "leaking param: args to result ~r0 level=1"
152	for i := 0; i < len(args); i++ {
153		switch x := args[i].(type) {
154		case nil:
155			println("is nil")
156		case int32:
157			println("is int32")
158		case *int32:
159			println("is *int32")
160			return x
161		case string:
162			println("is string")
163		}
164	}
165	return nil
166}
167
168func TFooL2() {
169	a := int32(1) // ERROR "moved to heap: a"
170	b := "cat"
171	c := &a
172	s := []interface{}{a, b, c} // ERROR "a escapes to heap" "b escapes to heap" "\[\]interface {}{...} does not escape"
173	isink = FooL(s)
174}
175