mirror of
https://github.com/golang/go.git
synced 2026-01-29 07:02:05 +03:00
This change improves the concrete type analysis in the devirtualizer,
it not longer relies on ir.Reassigned, it now statically tries to
determine the concrete type of an interface, even when assigned
multiple times, following type assertions and iface conversions.
Alternative to CL 649195
Updates #69521
Fixes #64824
Change-Id: Ib1656e19f3619ab2e1e6b2c78346cc320490b2af
GitHub-Last-Rev: e8fa0b12f0
GitHub-Pull-Request: golang/go#71935
Reviewed-on: https://go-review.googlesource.com/c/go/+/652036
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Keith Randall <khr@golang.org>
1278 lines
34 KiB
Go
1278 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"
|
|
}
|
|
}
|
|
|
|
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"
|
|
}
|