|  | // run | 
|  |  | 
|  | // Copyright 2009 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package main | 
|  |  | 
|  | // Test for correct heap-moving of escaped variables. | 
|  | // It is hard to check for the allocations, but it is easy | 
|  | // to check that if you call the function twice at the | 
|  | // same stack level, the pointers returned should be | 
|  | // different. | 
|  |  | 
|  | var bad = false | 
|  |  | 
|  | var allptr = make([]*int, 0, 100) | 
|  |  | 
|  | func noalias(p, q *int, s string) { | 
|  | n := len(allptr) | 
|  | *p = -(n + 1) | 
|  | *q = -(n + 2) | 
|  | allptr = allptr[0 : n+2] | 
|  | allptr[n] = p | 
|  | allptr[n+1] = q | 
|  | n += 2 | 
|  | for i := 0; i < n; i++ { | 
|  | if allptr[i] != nil && *allptr[i] != -(i+1) { | 
|  | println("aliased pointers", -(i + 1), *allptr[i], "after", s) | 
|  | allptr[i] = nil | 
|  | bad = true | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func val(p, q *int, v int, s string) { | 
|  | if *p != v { | 
|  | println("wrong value want", v, "got", *p, "after", s) | 
|  | bad = true | 
|  | } | 
|  | if *q != v+1 { | 
|  | println("wrong value want", v+1, "got", *q, "after", s) | 
|  | bad = true | 
|  | } | 
|  | } | 
|  |  | 
|  | func chk(p, q *int, v int, s string) { | 
|  | val(p, q, v, s) | 
|  | noalias(p, q, s) | 
|  | } | 
|  |  | 
|  | func chkalias(p, q *int, v int, s string) { | 
|  | if p != q { | 
|  | println("want aliased pointers but got different after", s) | 
|  | bad = true | 
|  | } | 
|  | if *q != v+1 { | 
|  | println("wrong value want", v+1, "got", *q, "after", s) | 
|  | bad = true | 
|  | } | 
|  | } | 
|  |  | 
|  | func i_escapes(x int) *int { | 
|  | var i int | 
|  | i = x | 
|  | return &i | 
|  | } | 
|  |  | 
|  | func j_escapes(x int) *int { | 
|  | var j int = x | 
|  | j = x | 
|  | return &j | 
|  | } | 
|  |  | 
|  | func k_escapes(x int) *int { | 
|  | k := x | 
|  | return &k | 
|  | } | 
|  |  | 
|  | func in_escapes(x int) *int { | 
|  | return &x | 
|  | } | 
|  |  | 
|  | func send(c chan int, x int) { | 
|  | c <- x | 
|  | } | 
|  |  | 
|  | func select_escapes(x int) *int { | 
|  | c := make(chan int) | 
|  | go send(c, x) | 
|  | select { | 
|  | case req := <-c: | 
|  | return &req | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func select_escapes1(x int, y int) (*int, *int) { | 
|  | c := make(chan int) | 
|  | var a [2]int | 
|  | var p [2]*int | 
|  | a[0] = x | 
|  | a[1] = y | 
|  | for i := 0; i < 2; i++ { | 
|  | go send(c, a[i]) | 
|  | select { | 
|  | case req := <-c: | 
|  | p[i] = &req | 
|  | } | 
|  | } | 
|  | return p[0], p[1] | 
|  | } | 
|  |  | 
|  | func range_escapes(x int) *int { | 
|  | var a [1]int | 
|  | a[0] = x | 
|  | for _, v := range a { | 
|  | return &v | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // *is* aliased | 
|  | func range_escapes2(x, y int) (*int, *int) { | 
|  | var a [2]int | 
|  | var p [2]*int | 
|  | a[0] = x | 
|  | a[1] = y | 
|  | var k, v int | 
|  | for k, v = range a { | 
|  | p[k] = &v | 
|  | } | 
|  | return p[0], p[1] | 
|  | } | 
|  |  | 
|  | // *is* aliased | 
|  | func for_escapes2(x int, y int) (*int, *int) { | 
|  | var p [2]*int | 
|  | n := 0 | 
|  | i := x | 
|  | for ; n < 2; i = y { | 
|  | p[n] = &i | 
|  | n++ | 
|  | } | 
|  | return p[0], p[1] | 
|  | } | 
|  |  | 
|  | func for_escapes3(x int, y int) (*int, *int) { | 
|  | var f [2]func() *int | 
|  | n := 0 | 
|  | for i := x; n < 2; i = y { | 
|  | p := new(int) | 
|  | *p = i | 
|  | f[n] = func() *int { return p } | 
|  | n++ | 
|  | } | 
|  | return f[0](), f[1]() | 
|  | } | 
|  |  | 
|  | func out_escapes(i int) (x int, p *int) { | 
|  | x = i | 
|  | p = &x // ERROR "address of out parameter" | 
|  | return | 
|  | } | 
|  |  | 
|  | func out_escapes_2(i int) (x int, p *int) { | 
|  | x = i | 
|  | return x, &x // ERROR "address of out parameter" | 
|  | } | 
|  |  | 
|  | func defer1(i int) (x int) { | 
|  | c := make(chan int) | 
|  | go func() { x = i; c <- 1 }() | 
|  | <-c | 
|  | return | 
|  | } | 
|  |  | 
|  | func main() { | 
|  | p, q := i_escapes(1), i_escapes(2) | 
|  | chk(p, q, 1, "i_escapes") | 
|  |  | 
|  | p, q = j_escapes(3), j_escapes(4) | 
|  | chk(p, q, 3, "j_escapes") | 
|  |  | 
|  | p, q = k_escapes(5), k_escapes(6) | 
|  | chk(p, q, 5, "k_escapes") | 
|  |  | 
|  | p, q = in_escapes(7), in_escapes(8) | 
|  | chk(p, q, 7, "in_escapes") | 
|  |  | 
|  | p, q = select_escapes(9), select_escapes(10) | 
|  | chk(p, q, 9, "select_escapes") | 
|  |  | 
|  | p, q = select_escapes1(11, 12) | 
|  | chk(p, q, 11, "select_escapes1") | 
|  |  | 
|  | p, q = range_escapes(13), range_escapes(14) | 
|  | chk(p, q, 13, "range_escapes") | 
|  |  | 
|  | p, q = range_escapes2(101, 102) | 
|  | chkalias(p, q, 101, "range_escapes2") | 
|  |  | 
|  | p, q = for_escapes2(103, 104) | 
|  | chkalias(p, q, 103, "for_escapes2") | 
|  |  | 
|  | p, q = for_escapes3(105, 106) | 
|  | chk(p, q, 105, "for_escapes3") | 
|  |  | 
|  | _, p = out_escapes(15) | 
|  | _, q = out_escapes(16) | 
|  | chk(p, q, 15, "out_escapes") | 
|  |  | 
|  | _, p = out_escapes_2(17) | 
|  | _, q = out_escapes_2(18) | 
|  | chk(p, q, 17, "out_escapes_2") | 
|  |  | 
|  | x := defer1(20) | 
|  | if x != 20 { | 
|  | println("defer failed", x) | 
|  | bad = true | 
|  | } | 
|  |  | 
|  | if bad { | 
|  | panic("BUG: no escape") | 
|  | } | 
|  | } |