go/test/devirtualization.go
Mateusz Poliwczak 5a9ef44bc0 cmd/compile/internal/devirtualize: fix OCONVNOP assertion
Fixes #75863

Change-Id: I1e5a0f3880dcd5f820a5b6f4540c49b16a6a6964
Reviewed-on: https://go-review.googlesource.com/c/go/+/711141
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Lasse Folger <lassefolger@google.com>
Auto-Submit: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-10-14 09:33:37 -07:00

1283 lines
34 KiB
Go

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