1package main
2
3import "runtime"
4
5func final1a(x *int) int {
6	print(x) // @pointsto new@newint:10
7	return *x
8}
9
10func final1b(x *bool) {
11	print(x) // @pointsto
12}
13
14func runtimeSetFinalizer1() {
15	x := new(int)                    // @line newint
16	runtime.SetFinalizer(x, final1a) // ok: final1a's result is ignored
17	runtime.SetFinalizer(x, final1b) // param type mismatch: no effect
18}
19
20// @calls main.runtimeSetFinalizer1 -> main.final1a
21// @calls main.runtimeSetFinalizer1 -> main.final1b
22
23func final2a(x *bool) {
24	print(x) // @pointsto new@newbool1:10 | new@newbool2:10
25}
26
27func final2b(x *bool) {
28	print(x) // @pointsto new@newbool1:10 | new@newbool2:10
29}
30
31func runtimeSetFinalizer2() {
32	x := new(bool) // @line newbool1
33	f := final2a
34	if unknown {
35		x = new(bool) // @line newbool2
36		f = final2b
37	}
38	runtime.SetFinalizer(x, f)
39}
40
41// @calls main.runtimeSetFinalizer2 -> main.final2a
42// @calls main.runtimeSetFinalizer2 -> main.final2b
43
44type T int
45
46func (t *T) finalize() {
47	print(t) // @pointsto new@final3:10
48}
49
50func runtimeSetFinalizer3() {
51	x := new(T) // @line final3
52	runtime.SetFinalizer(x, (*T).finalize)
53}
54
55// @calls main.runtimeSetFinalizer3 -> (*main.T).finalize$thunk
56
57// I hope I never live to see this code in the wild.
58var setFinalizer = runtime.SetFinalizer
59
60func final4(x *int) {
61	print(x) // @pointsto new@finalIndirect:10
62}
63
64func runtimeSetFinalizerIndirect() {
65	// In an indirect call, the shared contour for SetFinalizer is
66	// used, i.e. the call is not inlined and appears in the call graph.
67	x := new(int) // @line finalIndirect
68	setFinalizer(x, final4)
69}
70
71// Exercise the elimination of SetFinalizer
72// constraints with non-pointer operands.
73func runtimeSetFinalizerNonpointer() {
74	runtime.SetFinalizer(nil, (*T).finalize) // x is a non-pointer
75	runtime.SetFinalizer((*T).finalize, nil) // f is a non-pointer
76}
77
78// @calls main.runtimeSetFinalizerIndirect -> runtime.SetFinalizer
79// @calls runtime.SetFinalizer -> main.final4
80
81func main() {
82	runtimeSetFinalizer1()
83	runtimeSetFinalizer2()
84	runtimeSetFinalizer3()
85	runtimeSetFinalizerIndirect()
86	runtimeSetFinalizerNonpointer()
87}
88
89var unknown bool // defeat dead-code elimination
90