| // errorcheck -0 -m | |
| // Copyright 2025 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 escape | |
| type M interface{ M() } | |
| type A interface{ A() } | |
| type C interface{ C() } | |
| type Impl struct{} | |
| func (*Impl) M() {} // ERROR "can inline \(\*Impl\).M$" | |
| func (*Impl) A() {} // ERROR "can inline \(\*Impl\).A$" | |
| type Impl2 struct{} | |
| func (*Impl2) M() {} // ERROR "can inline \(\*Impl2\).M$" | |
| func (*Impl2) A() {} // ERROR "can inline \(\*Impl2\).A$" | |
| type CImpl struct{} | |
| func (CImpl) C() {} // ERROR "can inline CImpl.C$" | |
| func typeAsserts() { | |
| var a M = &Impl{} // ERROR "&Impl{} does not escape$" | |
| a.(M).M() // ERROR "devirtualizing a.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| a.(A).A() // ERROR "devirtualizing a.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| a.(*Impl).M() // ERROR "inlining call to \(\*Impl\).M" | |
| a.(*Impl).A() // ERROR "inlining call to \(\*Impl\).A" | |
| v := a.(M) | |
| v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| v.(A).A() // ERROR "devirtualizing v.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| v.(*Impl).A() // ERROR "inlining call to \(\*Impl\).A" | |
| v.(*Impl).M() // ERROR "inlining call to \(\*Impl\).M" | |
| v2 := a.(A) | |
| v2.A() // ERROR "devirtualizing v2.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| v2.(M).M() // ERROR "devirtualizing v2.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| v2.(*Impl).A() // ERROR "inlining call to \(\*Impl\).A" | |
| v2.(*Impl).M() // ERROR "inlining call to \(\*Impl\).M" | |
| a.(M).(A).A() // ERROR "devirtualizing a.\(M\).\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| a.(A).(M).M() // ERROR "devirtualizing a.\(A\).\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| a.(M).(A).(*Impl).A() // ERROR "inlining call to \(\*Impl\).A" | |
| a.(A).(M).(*Impl).M() // ERROR "inlining call to \(\*Impl\).M" | |
| any(a).(M).M() // ERROR "devirtualizing any\(a\).\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| any(a).(A).A() // ERROR "devirtualizing any\(a\).\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| any(a).(M).(any).(A).A() // ERROR "devirtualizing any\(a\).\(M\).\(any\).\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| c := any(a) | |
| c.(A).A() // ERROR "devirtualizing c.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| c.(M).M() // ERROR "devirtualizing c.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| M(a).M() // ERROR "devirtualizing M\(a\).M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| M(M(a)).M() // ERROR "devirtualizing M\(M\(a\)\).M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| a2 := a.(A) | |
| A(a2).A() // ERROR "devirtualizing A\(a2\).A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| A(A(a2)).A() // ERROR "devirtualizing A\(A\(a2\)\).A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| { | |
| var a C = &CImpl{} // ERROR "&CImpl{} does not escape$" | |
| a.(any).(C).C() // ERROR "devirtualizing a.\(any\).\(C\).C to \*CImpl$" "inlining call to CImpl.C" | |
| a.(any).(*CImpl).C() // ERROR "inlining call to CImpl.C" | |
| } | |
| } | |
| func typeAssertsWithOkReturn() { | |
| { | |
| var a M = &Impl{} // ERROR "&Impl{} does not escape$" | |
| if v, ok := a.(M); ok { | |
| v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| } | |
| } | |
| { | |
| var a M = &Impl{} // ERROR "&Impl{} does not escape$" | |
| if v, ok := a.(A); ok { | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| } | |
| { | |
| var a M = &Impl{} // ERROR "&Impl{} does not escape$" | |
| v, ok := a.(M) | |
| if ok { | |
| v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| } | |
| } | |
| { | |
| var a M = &Impl{} // ERROR "&Impl{} does not escape$" | |
| v, ok := a.(A) | |
| if ok { | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| } | |
| { | |
| var a M = &Impl{} // ERROR "&Impl{} does not escape$" | |
| v, ok := a.(*Impl) | |
| if ok { | |
| v.A() // ERROR "inlining call to \(\*Impl\).A" | |
| v.M() // ERROR "inlining call to \(\*Impl\).M" | |
| } | |
| } | |
| { | |
| var a M = &Impl{} // ERROR "&Impl{} does not escape$" | |
| v, _ := a.(M) | |
| v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| } | |
| { | |
| var a M = &Impl{} // ERROR "&Impl{} does not escape$" | |
| v, _ := a.(A) | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var a M = &Impl{} // ERROR "&Impl{} does not escape$" | |
| v, _ := a.(*Impl) | |
| v.A() // ERROR "inlining call to \(\*Impl\).A" | |
| v.M() // ERROR "inlining call to \(\*Impl\).M" | |
| } | |
| { | |
| a := newM() // ERROR "&Impl{} does not escape$" "inlining call to newM" | |
| callA(a) // ERROR "devirtualizing m.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" "inlining call to callA" | |
| callIfA(a) // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" "inlining call to callIfA" | |
| } | |
| { | |
| _, a := newM2ret() // ERROR "&Impl{} does not escape$" "inlining call to newM2ret" | |
| callA(a) // ERROR "devirtualizing m.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" "inlining call to callA" | |
| callIfA(a) // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" "inlining call to callIfA" | |
| } | |
| { | |
| var a M = &Impl{} // ERROR "&Impl{} does not escape$" | |
| // Note the !ok condition, devirtualizing here is fine. | |
| if v, ok := a.(M); !ok { | |
| v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| } | |
| } | |
| { | |
| var a A = newImplNoInline() | |
| if v, ok := a.(M); ok { | |
| v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| } | |
| } | |
| { | |
| var impl2InA A = &Impl2{} // ERROR "&Impl2{} does not escape$" | |
| var a A | |
| a, _ = impl2InA.(*Impl) | |
| // a now contains the zero value of *Impl | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| a := newANoInline() | |
| a.A() | |
| } | |
| { | |
| _, a := newANoInlineRet2() | |
| a.A() | |
| } | |
| } | |
| func newM() M { // ERROR "can inline newM$" | |
| return &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| } | |
| func newM2ret() (int, M) { // ERROR "can inline newM2ret$" | |
| return -1, &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| } | |
| func callA(m M) { // ERROR "can inline callA$" "leaking param: m$" | |
| m.(A).A() | |
| } | |
| func callIfA(m M) { // ERROR "can inline callIfA$" "leaking param: m$" | |
| if v, ok := m.(A); ok { | |
| v.A() | |
| } | |
| } | |
| //go:noinline | |
| func newImplNoInline() *Impl { | |
| return &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| } | |
| //go:noinline | |
| func newImpl2ret2() (string, *Impl2) { | |
| return "str", &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| } | |
| //go:noinline | |
| func newImpl2() *Impl2 { | |
| return &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| } | |
| //go:noinline | |
| func newANoInline() A { | |
| return &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| } | |
| //go:noinline | |
| func newANoInlineRet2() (string, A) { | |
| return "", &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| } | |
| func testTypeSwitch() { | |
| { | |
| var v A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| switch v := v.(type) { | |
| case A: | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| case M: | |
| v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| } | |
| } | |
| { | |
| var v A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| switch v := v.(type) { | |
| case A: | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| case M: | |
| v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| v = &Impl{} // ERROR "&Impl{} does not escape$" | |
| v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| } | |
| v.(M).M() // ERROR "devirtualizing v.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| } | |
| { | |
| var v A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| switch v1 := v.(type) { | |
| case A: | |
| v1.A() | |
| case M: | |
| v1.M() | |
| v = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| } | |
| } | |
| { | |
| var v A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| switch v := v.(type) { | |
| case A: | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| case M: | |
| v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| case C: | |
| v.C() | |
| } | |
| } | |
| { | |
| var v A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| switch v := v.(type) { | |
| case M: | |
| v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| default: | |
| panic("does not implement M") // ERROR ".does not implement M. escapes to heap$" | |
| } | |
| } | |
| } | |
| func differentTypeAssign() { | |
| { | |
| var a A | |
| a = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| a = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| a.A() | |
| } | |
| { | |
| a := A(&Impl{}) // ERROR "&Impl{} escapes to heap$" | |
| a = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| a.A() | |
| } | |
| { | |
| a := A(&Impl{}) // ERROR "&Impl{} escapes to heap$" | |
| a.A() | |
| a = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| } | |
| { | |
| a := A(&Impl{}) // ERROR "&Impl{} escapes to heap$" | |
| a = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| var asAny any = a | |
| asAny.(A).A() | |
| } | |
| { | |
| a := A(&Impl{}) // ERROR "&Impl{} escapes to heap$" | |
| var asAny any = a | |
| asAny = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| asAny.(A).A() | |
| } | |
| { | |
| a := A(&Impl{}) // ERROR "&Impl{} escapes to heap$" | |
| var asAny any = a | |
| asAny.(A).A() | |
| asAny = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var a A | |
| a = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| a = newImpl2() | |
| a.A() | |
| } | |
| { | |
| var a A | |
| a = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| _, a = newImpl2ret2() | |
| a.A() | |
| } | |
| } | |
| func assignWithTypeAssert() { | |
| { | |
| var i1 A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| var i2 A = &Impl2{} // ERROR "&Impl2{} does not escape$" | |
| i1 = i2.(*Impl) // this will panic | |
| i1.A() // ERROR "devirtualizing i1.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| i2.A() // ERROR "devirtualizing i2.A to \*Impl2$" "inlining call to \(\*Impl2\).A" | |
| } | |
| { | |
| var i1 A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| var i2 A = &Impl2{} // ERROR "&Impl2{} does not escape$" | |
| i1, _ = i2.(*Impl) // i1 is going to be nil | |
| i1.A() // ERROR "devirtualizing i1.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| i2.A() // ERROR "devirtualizing i2.A to \*Impl2$" "inlining call to \(\*Impl2\).A" | |
| } | |
| } | |
| func nilIface() { | |
| { | |
| var v A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| v = nil | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var v A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| v = nil | |
| } | |
| { | |
| var nilIface A | |
| var v A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| v = nilIface | |
| } | |
| { | |
| var nilIface A | |
| var v A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| v = nilIface | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var v A | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| v = &Impl{} // ERROR "&Impl{} does not escape$" | |
| } | |
| { | |
| var v A | |
| var v2 A = v | |
| v2.A() // ERROR "devirtualizing v2.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| v2 = &Impl{} // ERROR "&Impl{} does not escape$" | |
| } | |
| { | |
| var v A | |
| v.A() | |
| } | |
| { | |
| var v A | |
| var v2 A = v | |
| v2.A() | |
| } | |
| { | |
| var v A | |
| var v2 A | |
| v2 = v | |
| v2.A() | |
| } | |
| } | |
| func longDevirtTest() { | |
| var a interface { | |
| M | |
| A | |
| } = &Impl{} // ERROR "&Impl{} does not escape$" | |
| { | |
| var b A = a | |
| b.A() // ERROR "devirtualizing b.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| b.(M).M() // ERROR "devirtualizing b.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| } | |
| { | |
| var b M = a | |
| b.M() // ERROR "devirtualizing b.M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| b.(A).A() // ERROR "devirtualizing b.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var b A = a.(M).(A) | |
| b.A() // ERROR "devirtualizing b.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| b.(M).M() // ERROR "devirtualizing b.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| } | |
| { | |
| var b M = a.(A).(M) | |
| b.M() // ERROR "devirtualizing b.M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| b.(A).A() // ERROR "devirtualizing b.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| if v, ok := a.(A); ok { | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| if v, ok := a.(M); ok { | |
| v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| } | |
| { | |
| var c A = a | |
| if v, ok := c.(A); ok { | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| c = &Impl{} // ERROR "&Impl{} does not escape$" | |
| if v, ok := c.(M); ok { | |
| v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| } | |
| if v, ok := c.(interface { | |
| A | |
| M | |
| }); ok { | |
| v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| } | |
| } | |
| func deferDevirt() { | |
| var a A | |
| defer func() { // ERROR "can inline deferDevirt.func1$" "func literal does not escape$" | |
| a = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| }() | |
| a = &Impl{} // ERROR "&Impl{} does not escape$" | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| func deferNoDevirt() { | |
| var a A | |
| defer func() { // ERROR "can inline deferNoDevirt.func1$" "func literal does not escape$" | |
| a = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| }() | |
| a = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| a.A() | |
| } | |
| //go:noinline | |
| func closureDevirt() { | |
| var a A | |
| func() { // ERROR "func literal does not escape$" | |
| // defer so that it does not lnline. | |
| defer func() {}() // ERROR "can inline closureDevirt.func1.1$" "func literal does not escape$" | |
| a = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| }() | |
| a = &Impl{} // ERROR "&Impl{} does not escape$" | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| //go:noinline | |
| func closureNoDevirt() { | |
| var a A | |
| func() { // ERROR "func literal does not escape$" | |
| // defer so that it does not lnline. | |
| defer func() {}() // ERROR "can inline closureNoDevirt.func1.1$" "func literal does not escape$" | |
| a = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| }() | |
| a = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| a.A() | |
| } | |
| var global = "1" | |
| func closureDevirt2() { | |
| var a A | |
| a = &Impl{} // ERROR "&Impl{} does not escape$" | |
| c := func() { // ERROR "can inline closureDevirt2.func1$" "func literal does not escape$" | |
| a = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| } | |
| if global == "1" { | |
| c = func() { // ERROR "can inline closureDevirt2.func2$" "func literal does not escape$" | |
| a = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| } | |
| } | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| c() | |
| } | |
| func closureNoDevirt2() { | |
| var a A | |
| a = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| c := func() { // ERROR "can inline closureNoDevirt2.func1$" "func literal does not escape$" | |
| a = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| } | |
| if global == "1" { | |
| c = func() { // ERROR "can inline closureNoDevirt2.func2$" "func literal does not escape$" | |
| a = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| } | |
| } | |
| a.A() | |
| c() | |
| } | |
| //go:noinline | |
| func closureDevirt3() { | |
| var a A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| func() { // ERROR "func literal does not escape$" | |
| // defer so that it does not lnline. | |
| defer func() {}() // ERROR "can inline closureDevirt3.func1.1$" "func literal does not escape$" | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| }() | |
| func() { // ERROR "can inline closureDevirt3.func2$" | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| }() // ERROR "inlining call to closureDevirt3.func2" "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| //go:noinline | |
| func closureNoDevirt3() { | |
| var a A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| func() { // ERROR "func literal does not escape$" | |
| // defer so that it does not lnline. | |
| defer func() {}() // ERROR "can inline closureNoDevirt3.func1.1$" "func literal does not escape$" | |
| a.A() | |
| }() | |
| func() { // ERROR "can inline closureNoDevirt3.func2$" | |
| a.A() | |
| }() // ERROR "inlining call to closureNoDevirt3.func2" | |
| a = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| } | |
| //go:noinline | |
| func varDeclaredInClosureReferencesOuter() { | |
| var a A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| func() { // ERROR "func literal does not escape$" | |
| // defer for noinline | |
| defer func() {}() // ERROR "can inline varDeclaredInClosureReferencesOuter.func1.1$" "func literal does not escape$" | |
| var v A = a | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| }() | |
| func() { // ERROR "func literal does not escape$" | |
| // defer for noinline | |
| defer func() {}() // ERROR "can inline varDeclaredInClosureReferencesOuter.func2.1$" "func literal does not escape$" | |
| var v A = a | |
| v = &Impl{} // ERROR "&Impl{} does not escape$" | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| }() | |
| var b A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| func() { // ERROR "func literal does not escape$" | |
| // defer for noinline | |
| defer func() {}() // ERROR "can inline varDeclaredInClosureReferencesOuter.func3.1$" "func literal does not escape$" | |
| var v A = b | |
| v = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| v.A() | |
| }() | |
| func() { // ERROR "func literal does not escape$" | |
| // defer for noinline | |
| defer func() {}() // ERROR "can inline varDeclaredInClosureReferencesOuter.func4.1$" "func literal does not escape$" | |
| var v A = b | |
| v.A() | |
| v = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| }() | |
| } | |
| //go:noinline | |
| func testNamedReturn0() (v A) { | |
| v = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| v.A() | |
| return | |
| } | |
| //go:noinline | |
| func testNamedReturn1() (v A) { | |
| v = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| v.A() | |
| return &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| } | |
| func testNamedReturns3() (v A) { | |
| v = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| defer func() { // ERROR "can inline testNamedReturns3.func1$" "func literal does not escape$" | |
| v.A() | |
| }() | |
| v.A() | |
| return &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| } | |
| var ( | |
| globalImpl = &Impl{} | |
| globalImpl2 = &Impl2{} | |
| globalA A = &Impl{} | |
| globalM M = &Impl{} | |
| ) | |
| func globals() { | |
| { | |
| globalA.A() | |
| globalA.(M).M() | |
| globalM.M() | |
| globalM.(A).A() | |
| a := globalA | |
| a.A() | |
| a.(M).M() | |
| m := globalM | |
| m.M() | |
| m.(A).A() | |
| } | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| a = globalImpl | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| a = A(globalImpl) | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| a = M(globalImpl).(A) | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| a = globalA.(*Impl) | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| a = globalM.(*Impl) | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| a = globalImpl2 | |
| a.A() | |
| } | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| a = globalA | |
| a.A() | |
| } | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| a = globalM.(A) | |
| a.A() | |
| } | |
| } | |
| func mapsDevirt() { | |
| { | |
| m := make(map[int]*Impl) // ERROR "make\(map\[int\]\*Impl\) does not escape$" | |
| var v A = m[0] | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| v.(M).M() // ERROR "devirtualizing v.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| } | |
| { | |
| m := make(map[int]*Impl) // ERROR "make\(map\[int\]\*Impl\) does not escape$" | |
| var v A | |
| var ok bool | |
| if v, ok = m[0]; ok { | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| m := make(map[int]*Impl) // ERROR "make\(map\[int\]\*Impl\) does not escape$" | |
| var v A | |
| v, _ = m[0] | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| } | |
| func mapsNoDevirt() { | |
| { | |
| m := make(map[int]*Impl) // ERROR "make\(map\[int\]\*Impl\) does not escape$" | |
| var v A = m[0] | |
| v.A() | |
| v = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| v.(M).M() | |
| } | |
| { | |
| m := make(map[int]*Impl) // ERROR "make\(map\[int\]\*Impl\) does not escape$" | |
| var v A | |
| var ok bool | |
| if v, ok = m[0]; ok { | |
| v.A() | |
| } | |
| v = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| v.A() | |
| } | |
| { | |
| m := make(map[int]*Impl) // ERROR "make\(map\[int\]\*Impl\) does not escape$" | |
| var v A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| v, _ = m[0] | |
| v = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| v.A() | |
| } | |
| { | |
| m := make(map[int]A) // ERROR "make\(map\[int\]A\) does not escape$" | |
| var v A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| v = m[0] | |
| v.A() | |
| } | |
| { | |
| m := make(map[int]A) // ERROR "make\(map\[int\]A\) does not escape$" | |
| var v A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| var ok bool | |
| if v, ok = m[0]; ok { | |
| v.A() | |
| } | |
| v.A() | |
| } | |
| { | |
| m := make(map[int]A) // ERROR "make\(map\[int\]A\) does not escape$" | |
| var v A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| v, _ = m[0] | |
| v.A() | |
| } | |
| } | |
| func chanDevirt() { | |
| { | |
| m := make(chan *Impl) | |
| var v A = <-m | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| m := make(chan *Impl) | |
| var v A | |
| v = <-m | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| m := make(chan *Impl) | |
| var v A | |
| v, _ = <-m | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| m := make(chan *Impl) | |
| var v A | |
| var ok bool | |
| if v, ok = <-m; ok { | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| m := make(chan *Impl) | |
| var v A | |
| var ok bool | |
| if v, ok = <-m; ok { | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| select { | |
| case <-m: | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| case v = <-m: | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| case v, ok = <-m: | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| } | |
| } | |
| func chanNoDevirt() { | |
| { | |
| m := make(chan *Impl) | |
| var v A = <-m | |
| v = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| v.A() | |
| } | |
| { | |
| m := make(chan *Impl) | |
| var v A | |
| v = <-m | |
| v = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| v.A() | |
| } | |
| { | |
| m := make(chan *Impl) | |
| var v A | |
| v, _ = <-m | |
| v = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| v.A() | |
| } | |
| { | |
| m := make(chan *Impl) | |
| var v A | |
| var ok bool | |
| if v, ok = <-m; ok { | |
| v.A() | |
| } | |
| v = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| v.A() | |
| } | |
| { | |
| m := make(chan *Impl) | |
| var v A = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| var ok bool | |
| if v, ok = <-m; ok { | |
| v.A() | |
| } | |
| } | |
| { | |
| m := make(chan *Impl) | |
| var v A = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| select { | |
| case v = <-m: | |
| v.A() | |
| } | |
| v.A() | |
| } | |
| { | |
| m := make(chan *Impl) | |
| var v A = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| select { | |
| case v, _ = <-m: | |
| v.A() | |
| } | |
| v.A() | |
| } | |
| { | |
| m := make(chan A) | |
| var v A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| v = <-m | |
| v.A() | |
| } | |
| { | |
| m := make(chan A) | |
| var v A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| v, _ = <-m | |
| v.A() | |
| } | |
| { | |
| m := make(chan A) | |
| var v A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| var ok bool | |
| if v, ok = <-m; ok { | |
| v.A() | |
| } | |
| } | |
| { | |
| m := make(chan A) | |
| var v A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| select { | |
| case v = <-m: | |
| v.A() | |
| } | |
| v.A() | |
| } | |
| { | |
| m := make(chan A) | |
| var v A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| select { | |
| case v, _ = <-m: | |
| v.A() | |
| } | |
| v.A() | |
| } | |
| } | |
| func rangeDevirt() { | |
| { | |
| var v A | |
| m := make(map[*Impl]struct{}) // ERROR "make\(map\[\*Impl\]struct {}\) does not escape$" | |
| v = &Impl{} // ERROR "&Impl{} does not escape$" | |
| for v = range m { | |
| } | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var v A | |
| m := make(map[*Impl]*Impl) // ERROR "make\(map\[\*Impl\]\*Impl\) does not escape$" | |
| v = &Impl{} // ERROR "&Impl{} does not escape$" | |
| for v = range m { | |
| } | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var v A | |
| m := make(map[*Impl]*Impl) // ERROR "make\(map\[\*Impl\]\*Impl\) does not escape$" | |
| v = &Impl{} // ERROR "&Impl{} does not escape$" | |
| for _, v = range m { | |
| } | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var v A | |
| m := make(chan *Impl) | |
| v = &Impl{} // ERROR "&Impl{} does not escape$" | |
| for v = range m { | |
| } | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var v A | |
| m := []*Impl{} // ERROR "\[\]\*Impl{} does not escape$" | |
| v = &Impl{} // ERROR "&Impl{} does not escape$" | |
| for _, v = range m { | |
| } | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var v A | |
| v = &Impl{} // ERROR "&Impl{} does not escape$" | |
| impl := &Impl{} // ERROR "&Impl{} does not escape$" | |
| i := 0 | |
| for v = impl; i < 10; i++ { | |
| } | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var v A | |
| v = &Impl{} // ERROR "&Impl{} does not escape$" | |
| impl := &Impl{} // ERROR "&Impl{} does not escape$" | |
| i := 0 | |
| for v = impl; i < 10; i++ { | |
| } | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var v A | |
| m := [1]*Impl{&Impl{}} // ERROR "&Impl{} does not escape$" | |
| v = &Impl{} // ERROR "&Impl{} does not escape$" | |
| for _, v = range m { | |
| } | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var v A | |
| m := [1]*Impl{&Impl{}} // ERROR "&Impl{} does not escape$" | |
| v = &Impl{} // ERROR "&Impl{} does not escape$" | |
| for _, v = range &m { | |
| } | |
| v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| } | |
| func rangeNoDevirt() { | |
| { | |
| var v A = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| m := make(map[*Impl]struct{}) // ERROR "make\(map\[\*Impl\]struct {}\) does not escape$" | |
| for v = range m { | |
| } | |
| v.A() | |
| } | |
| { | |
| var v A = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| m := make(map[*Impl]*Impl) // ERROR "make\(map\[\*Impl\]\*Impl\) does not escape$" | |
| for v = range m { | |
| } | |
| v.A() | |
| } | |
| { | |
| var v A = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| m := make(map[*Impl]*Impl) // ERROR "make\(map\[\*Impl\]\*Impl\) does not escape$" | |
| for _, v = range m { | |
| } | |
| v.A() | |
| } | |
| { | |
| var v A = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| m := make(chan *Impl) | |
| for v = range m { | |
| } | |
| v.A() | |
| } | |
| { | |
| var v A = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| m := []*Impl{} // ERROR "\[\]\*Impl{} does not escape$" | |
| for _, v = range m { | |
| } | |
| v.A() | |
| } | |
| { | |
| var v A | |
| v = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| impl := &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| i := 0 | |
| for v = impl; i < 10; i++ { | |
| } | |
| v.A() | |
| } | |
| { | |
| var v A | |
| v = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| impl := &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| i := 0 | |
| for v = impl; i < 10; i++ { | |
| } | |
| v.A() | |
| } | |
| { | |
| var v A | |
| m := [1]*Impl{&Impl{}} // ERROR "&Impl{} escapes to heap$" | |
| v = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| for _, v = range m { | |
| } | |
| v.A() | |
| } | |
| { | |
| var v A | |
| m := [1]*Impl{&Impl{}} // ERROR "&Impl{} escapes to heap$" | |
| v = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| for _, v = range &m { | |
| } | |
| v.A() | |
| } | |
| { | |
| var v A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| m := make(map[A]struct{}) // ERROR "make\(map\[A\]struct {}\) does not escape$" | |
| for v = range m { | |
| } | |
| v.A() | |
| } | |
| { | |
| var v A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| m := make(map[A]A) // ERROR "make\(map\[A\]A\) does not escape$" | |
| for v = range m { | |
| } | |
| v.A() | |
| } | |
| { | |
| var v A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| m := make(map[A]A) // ERROR "make\(map\[A\]A\) does not escape$" | |
| for _, v = range m { | |
| } | |
| v.A() | |
| } | |
| { | |
| var v A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| m := make(chan A) | |
| for v = range m { | |
| } | |
| v.A() | |
| } | |
| { | |
| var v A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| m := []A{} // ERROR "\[\]A{} does not escape$" | |
| for _, v = range m { | |
| } | |
| v.A() | |
| } | |
| { | |
| var v A | |
| m := [1]A{&Impl{}} // ERROR "&Impl{} escapes to heap$" | |
| v = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| for _, v = range m { | |
| } | |
| v.A() | |
| } | |
| { | |
| var v A | |
| m := [1]A{&Impl{}} // ERROR "&Impl{} escapes to heap$" | |
| v = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| for _, v = range &m { | |
| } | |
| v.A() | |
| } | |
| } | |
| var globalInt = 1 | |
| func testIfInit() { | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| var i = &Impl{} // ERROR "&Impl{} does not escape$" | |
| if a = i; globalInt == 1 { | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| a.(M).M() // ERROR "devirtualizing a.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| } | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| var i2 = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| if a = i2; globalInt == 1 { | |
| a.A() | |
| } | |
| a.A() | |
| } | |
| } | |
| func testSwitchInit() { | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| var i = &Impl{} // ERROR "&Impl{} does not escape$" | |
| switch a = i; globalInt { | |
| case 12: | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| a.(M).M() // ERROR "devirtualizing a.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| } | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| var i2 = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| switch a = i2; globalInt { | |
| case 12: | |
| a.A() | |
| } | |
| a.A() | |
| } | |
| } | |
| type implWrapper Impl | |
| func (implWrapper) A() {} // ERROR "can inline implWrapper.A$" | |
| //go:noinline | |
| func devirtWrapperType() { | |
| { | |
| i := &Impl{} // ERROR "&Impl{} does not escape$" | |
| // This is an OCONVNOP, so we have to be careful, not to devirtualize it to Impl.A. | |
| var a A = (*implWrapper)(i) | |
| a.A() // ERROR "devirtualizing a.A to \*implWrapper$" "inlining call to implWrapper.A" | |
| } | |
| { | |
| i := Impl{} | |
| // This is an OCONVNOP, so we have to be careful, not to devirtualize it to Impl.A. | |
| var a A = (implWrapper)(i) // ERROR "implWrapper\(i\) does not escape$" | |
| a.A() // ERROR "devirtualizing a.A to implWrapper$" "inlining call to implWrapper.A" | |
| } | |
| { | |
| type anyWrapper any | |
| var foo any = &Impl{} // ERROR "&Impl\{\} does not escape" | |
| var bar anyWrapper = foo | |
| bar.(M).M() // ERROR "devirtualizing bar\.\(M\).M to \*Impl" "inlining call to \(\*Impl\)\.M" | |
| } | |
| } | |
| func selfAssigns() { | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} does not escape$" | |
| a = a | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} does not escape" | |
| var asAny any = a | |
| asAny = asAny | |
| asAny.(A).A() // ERROR "devirtualizing asAny.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} does not escape" | |
| var asAny any = a | |
| a = asAny.(A) | |
| asAny.(A).A() // ERROR "devirtualizing asAny.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| a.(A).A() // ERROR "devirtualizing a.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| b := a | |
| b.(A).A() // ERROR "devirtualizing b.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} does not escape" | |
| var asAny any = a | |
| asAny = asAny | |
| a = asAny.(A) | |
| asAny = a | |
| asAny.(A).A() // ERROR "devirtualizing asAny.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| asAny.(M).M() // ERROR "devirtualizing asAny.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M" | |
| } | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} does not escape" | |
| var asAny A = a | |
| a = asAny.(A) | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| { | |
| var a, b, c A | |
| c = &Impl{} // ERROR "&Impl{} does not escape$" | |
| a = c | |
| c = b | |
| b = c | |
| a = b | |
| b = a | |
| c = a | |
| a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A" | |
| } | |
| } | |
| func boolNoDevirt() { | |
| { | |
| m := make(map[int]*Impl) // ERROR "make\(map\[int\]\*Impl\) does not escape$" | |
| var v any = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| _, v = m[0] // ERROR ".autotmp_[0-9]+ escapes to heap$" | |
| v.(A).A() | |
| } | |
| { | |
| m := make(chan *Impl) | |
| var v any = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| select { | |
| case _, v = <-m: // ERROR ".autotmp_[0-9]+ escapes to heap$" | |
| } | |
| v.(A).A() | |
| } | |
| { | |
| m := make(chan *Impl) | |
| var v any = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| _, v = <-m // ERROR ".autotmp_[0-9]+ escapes to heap$" | |
| v.(A).A() | |
| } | |
| { | |
| var a any = 4 // ERROR "4 does not escape$" | |
| var v any = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| _, v = a.(int) // ERROR ".autotmp_[0-9]+ escapes to heap$" | |
| v.(A).A() | |
| } | |
| } | |
| func addrTaken() { | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| var ptrA = &a | |
| a.A() | |
| _ = ptrA | |
| } | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| var ptrA = &a | |
| *ptrA = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| a.A() | |
| } | |
| { | |
| var a A = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| var ptrA = &a | |
| *ptrA = &Impl2{} // ERROR "&Impl2{} escapes to heap$" | |
| a.A() | |
| } | |
| } | |
| func testInvalidAsserts() { | |
| any(0).(interface{ A() }).A() // ERROR "any\(0\) escapes to heap$" | |
| { | |
| var a M = &Impl{} // ERROR "&Impl{} escapes to heap$" | |
| a.(C).C() // this will panic | |
| a.(any).(C).C() // this will panic | |
| } | |
| { | |
| var a C = &CImpl{} // ERROR "&CImpl{} escapes to heap$" | |
| a.(M).M() // this will panic | |
| a.(any).(M).M() // this will panic | |
| } | |
| { | |
| var a C = &CImpl{} // ERROR "&CImpl{} does not escape$" | |
| // this will panic | |
| a.(M).(*Impl).M() // ERROR "inlining call to \(\*Impl\).M" | |
| // this will panic | |
| a.(any).(M).(*Impl).M() // ERROR "inlining call to \(\*Impl\).M" | |
| } | |
| } | |
| type namedBool bool | |
| func (namedBool) M() {} // ERROR "can inline namedBool.M$" | |
| //go:noinline | |
| func namedBoolTest() { | |
| m := map[int]int{} // ERROR "map\[int\]int{} does not escape" | |
| var ok namedBool | |
| _, ok = m[5] | |
| var i M = ok // ERROR "ok does not escape" | |
| i.M() // ERROR "devirtualizing i.M to namedBool$" "inlining call to namedBool.M" | |
| } | |
| //go:noinline | |
| func identicalType() { | |
| var i C = struct { | |
| CImpl | |
| }{} // ERROR "struct \{ CImpl \}\{\} escapes to heap" | |
| i = struct { | |
| CImpl | |
| }{} // ERROR "struct \{ CImpl \}\{\} escapes to heap" | |
| i.C() | |
| } | |
| type GenericAImpl[T any] struct{ _ T } | |
| //go:noinline | |
| func (GenericAImpl[T]) A() {} | |
| //go:noinline | |
| func generics() { | |
| { | |
| var i A = GenericAImpl[int]{} // ERROR "GenericAImpl\[int\]\{\} does not escape" | |
| i.A() // ERROR "devirtualizing i.A to GenericAImpl\[int\]" | |
| } | |
| { | |
| var i A = GenericAImpl[int]{} // ERROR "GenericAImpl\[int\]\{\} does not escape" | |
| i = GenericAImpl[int]{} // ERROR "GenericAImpl\[int\]\{\} does not escape" | |
| i.A() // ERROR "devirtualizing i.A to GenericAImpl\[int\]" | |
| } | |
| { | |
| var i A = GenericAImpl[int]{} // ERROR "GenericAImpl\[int\]\{\} escapes to heap" | |
| i = GenericAImpl[byte]{} // ERROR "GenericAImpl\[uint8\]\{\} escapes to heap" | |
| i.A() | |
| } | |
| } |