1// run
2
3// Copyright 2016 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// Previously, cmd/compile would rewrite
8//
9//     check(unsafe.Pointer(testMeth(1).Pointer()), unsafe.Pointer(testMeth(2).Pointer()))
10//
11// to
12//
13//     var autotmp_1 uintptr = testMeth(1).Pointer()
14//     var autotmp_2 uintptr = testMeth(2).Pointer()
15//     check(unsafe.Pointer(autotmp_1), unsafe.Pointer(autotmp_2))
16//
17// However, that means autotmp_1 is the only reference to the int
18// variable containing the value "1", but it's not a pointer type,
19// so it was at risk of being garbage collected by the evaluation of
20// testMeth(2).Pointer(), even though package unsafe's documentation
21// says the original code was allowed.
22//
23// Now cmd/compile rewrites it to
24//
25//     var autotmp_1 unsafe.Pointer = unsafe.Pointer(testMeth(1).Pointer())
26//     var autotmp_2 unsafe.Pointer = unsafe.Pointer(testMeth(2).Pointer())
27//     check(autotmp_1, autotmp_2)
28//
29// to ensure the pointed-to variables are visible to the GC.
30
31package main
32
33import (
34	"fmt"
35	"reflect"
36	"runtime"
37	"unsafe"
38)
39
40func main() {
41	// Test all the different ways we can invoke reflect.Value.Pointer.
42
43	// Direct method invocation.
44	check(unsafe.Pointer(testMeth(1).Pointer()), unsafe.Pointer(testMeth(2).Pointer()))
45
46	// Invocation via method expression.
47	check(unsafe.Pointer(reflect.Value.Pointer(testMeth(1))), unsafe.Pointer(reflect.Value.Pointer(testMeth(2))))
48
49	// Invocation via interface.
50	check(unsafe.Pointer(testInter(1).Pointer()), unsafe.Pointer(testInter(2).Pointer()))
51
52	// Invocation via method value.
53	check(unsafe.Pointer(testFunc(1)()), unsafe.Pointer(testFunc(2)()))
54}
55
56func check(p, q unsafe.Pointer) {
57	a, b := *(*int)(p), *(*int)(q)
58	if a != 1 || b != 2 {
59		fmt.Printf("got %v, %v; expected 1, 2\n", a, b)
60	}
61}
62
63func testMeth(x int) reflect.Value {
64	// Force GC to run.
65	runtime.GC()
66	return reflect.ValueOf(&x)
67}
68
69type Pointerer interface {
70	Pointer() uintptr
71}
72
73func testInter(x int) Pointerer {
74	return testMeth(x)
75}
76
77func testFunc(x int) func() uintptr {
78	return testMeth(x).Pointer
79}
80