1 | // Copyright 2021 The Go Authors. All rights reserved. |
---|---|
2 | // Use of this source code is governed by a BSD-style |
3 | // license that can be found in the LICENSE file. |
4 | |
5 | // go:build ignore |
6 | |
7 | package testdata |
8 | |
9 | type I interface { |
10 | Foo() |
11 | } |
12 | |
13 | type A struct { |
14 | f *I |
15 | } |
16 | |
17 | func (a A) Foo() {} |
18 | |
19 | type B struct{} |
20 | |
21 | func (b B) Foo() {} |
22 | |
23 | func Do(a A, i I, c bool) *I { |
24 | if c { |
25 | *a.f = a |
26 | } else { |
27 | a.f = &i |
28 | } |
29 | (*a.f).Foo() |
30 | return &i |
31 | } |
32 | |
33 | func Baz(a A, b B, c bool) { |
34 | x := Do(a, b, c) |
35 | (*x).Foo() |
36 | } |
37 | |
38 | // Relevant SSA: |
39 | // func Baz(a A, b B, c bool): |
40 | // t0 = local A (a) |
41 | // ... |
42 | // t5 = Do(t2, t4, c) |
43 | // t6 = *t5 |
44 | // t7 = invoke t6.Foo() |
45 | // return |
46 | |
47 | // func Do(a A, i I, c bool) *I: |
48 | // t0 = local A (a) |
49 | // *t0 = a |
50 | // ... |
51 | // if c goto 1 else 3 |
52 | // 1: |
53 | // t2 = &t0.f [#0] |
54 | // ... |
55 | // jump 2 |
56 | // 2: |
57 | // t6 = &t0.f [#0] |
58 | // ... |
59 | // t9 = invoke t8.Foo() |
60 | // return t1 |
61 | // 3: |
62 | // t10 = &t0.f [#0] alias between A.f and t10 |
63 | // *t10 = t1 alias between t10 and t1 |
64 | // jump 2 |
65 | |
66 | // The command a.f = &i introduces aliasing that results in |
67 | // A and B reaching both *A.f and return value of Do(a, b, c). |
68 | |
69 | // WANT: |
70 | // Baz: Do(t2, t4, c) -> Do; invoke t6.Foo() -> A.Foo, B.Foo |
71 | // Do: invoke t8.Foo() -> A.Foo, B.Foo |
72 |