// 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" }