1// run
2
3// Copyright 2009 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
7package main
8
9// Test for correct heap-moving of escaped variables.
10// It is hard to check for the allocations, but it is easy
11// to check that if you call the function twice at the
12// same stack level, the pointers returned should be
13// different.
14
15var bad = false
16
17var allptr = make([]*int, 0, 100)
18
19func noalias(p, q *int, s string) {
20	n := len(allptr)
21	*p = -(n + 1)
22	*q = -(n + 2)
23	allptr = allptr[0 : n+2]
24	allptr[n] = p
25	allptr[n+1] = q
26	n += 2
27	for i := 0; i < n; i++ {
28		if allptr[i] != nil && *allptr[i] != -(i+1) {
29			println("aliased pointers", -(i + 1), *allptr[i], "after", s)
30			allptr[i] = nil
31			bad = true
32		}
33	}
34}
35
36func val(p, q *int, v int, s string) {
37	if *p != v {
38		println("wrong value want", v, "got", *p, "after", s)
39		bad = true
40	}
41	if *q != v+1 {
42		println("wrong value want", v+1, "got", *q, "after", s)
43		bad = true
44	}
45}
46
47func chk(p, q *int, v int, s string) {
48	val(p, q, v, s)
49	noalias(p, q, s)
50}
51
52func chkalias(p, q *int, v int, s string) {
53	if p != q {
54		println("want aliased pointers but got different after", s)
55	}
56	if *q != v+1 {
57		println("wrong value want", v+1, "got", *q, "after", s)
58	}
59}
60
61func i_escapes(x int) *int {
62	var i int
63	i = x
64	return &i
65}
66
67func j_escapes(x int) *int {
68	var j int = x
69	j = x
70	return &j
71}
72
73func k_escapes(x int) *int {
74	k := x
75	return &k
76}
77
78func in_escapes(x int) *int {
79	return &x
80}
81
82func send(c chan int, x int) {
83	c <- x
84}
85
86func select_escapes(x int) *int {
87	c := make(chan int)
88	go send(c, x)
89	select {
90	case req := <-c:
91		return &req
92	}
93	return nil
94}
95
96func select_escapes1(x int, y int) (*int, *int) {
97	c := make(chan int)
98	var a [2]int
99	var p [2]*int
100	a[0] = x
101	a[1] = y
102	for i := 0; i < 2; i++ {
103		go send(c, a[i])
104		select {
105		case req := <-c:
106			p[i] = &req
107		}
108	}
109	return p[0], p[1]
110}
111
112func range_escapes(x int) *int {
113	var a [1]int
114	a[0] = x
115	for _, v := range a {
116		return &v
117	}
118	return nil
119}
120
121// *is* aliased
122func range_escapes2(x, y int) (*int, *int) {
123	var a [2]int
124	var p [2]*int
125	a[0] = x
126	a[1] = y
127	for k, v := range a {
128		p[k] = &v
129	}
130	return p[0], p[1]
131}
132
133// *is* aliased
134func for_escapes2(x int, y int) (*int, *int) {
135	var p [2]*int
136	n := 0
137	for i := x; n < 2; i = y {
138		p[n] = &i
139		n++
140	}
141	return p[0], p[1]
142}
143
144func for_escapes3(x int, y int) (*int, *int) {
145	var f [2]func() *int
146	n := 0
147	for i := x; n < 2; i = y {
148		p := new(int)
149		*p = i
150		f[n] = func() *int { return p }
151		n++
152	}
153	return f[0](), f[1]()
154}
155
156func out_escapes(i int) (x int, p *int) {
157	x = i
158	p = &x // ERROR "address of out parameter"
159	return
160}
161
162func out_escapes_2(i int) (x int, p *int) {
163	x = i
164	return x, &x // ERROR "address of out parameter"
165}
166
167func defer1(i int) (x int) {
168	c := make(chan int)
169	go func() { x = i; c <- 1 }()
170	<-c
171	return
172}
173
174func main() {
175	p, q := i_escapes(1), i_escapes(2)
176	chk(p, q, 1, "i_escapes")
177
178	p, q = j_escapes(3), j_escapes(4)
179	chk(p, q, 3, "j_escapes")
180
181	p, q = k_escapes(5), k_escapes(6)
182	chk(p, q, 5, "k_escapes")
183
184	p, q = in_escapes(7), in_escapes(8)
185	chk(p, q, 7, "in_escapes")
186
187	p, q = select_escapes(9), select_escapes(10)
188	chk(p, q, 9, "select_escapes")
189
190	p, q = select_escapes1(11, 12)
191	chk(p, q, 11, "select_escapes1")
192
193	p, q = range_escapes(13), range_escapes(14)
194	chk(p, q, 13, "range_escapes")
195
196	p, q = range_escapes2(101, 102)
197	chkalias(p, q, 101, "range_escapes2")
198
199	p, q = for_escapes2(103, 104)
200	chkalias(p, q, 103, "for_escapes2")
201
202	p, q = for_escapes3(105, 106)
203	chk(p, q, 105, "for_escapes3")
204
205	_, p = out_escapes(15)
206	_, q = out_escapes(16)
207	chk(p, q, 15, "out_escapes")
208
209	_, p = out_escapes_2(17)
210	_, q = out_escapes_2(18)
211	chk(p, q, 17, "out_escapes_2")
212
213	x := defer1(20)
214	if x != 20 {
215		println("defer failed", x)
216		bad = true
217	}
218
219	if bad {
220		panic("BUG: no escape")
221	}
222}
223