go/test/escape_iface.go
Matthew Dempsky abefcac10a cmd/compile: skip escape analysis diagnostics for OADDR
For most nodes (e.g., OPTRLIT, OMAKESLICE, OCONVIFACE), escape
analysis prints "escapes to heap" or "does not escape" to indicate
whether that node's allocation can be heap or stack allocated.

These messages are also emitted for OADDR, even though OADDR does not
actually allocate anything itself. Moreover, it's redundant because
escape analysis already prints "moved to heap" diagnostics when an
OADDR node like "&x" causes x to require heap allocation.

Because OADDR nodes don't allocate memory, my escape analysis rewrite
doesn't naturally emit the "escapes to heap" / "does not escape"
diagnostics for them. It's also non-trivial to replicate the exact
semantics esc.go uses for OADDR.

Since there are so many of these messages, I'm disabling them in this
CL by themselves. I modified esc.go to suppress the Warnl calls
without any other behavior changes, and then used a shell script to
automatically remove any ERROR messages mentioned by run.go in
"missing error" or "no match for" lines.

Fixes #16300.
Updates #23109.

Change-Id: I3993e2743c3ff83ccd0893f4e73b366ff8871a57
Reviewed-on: https://go-review.googlesource.com/c/go/+/170319
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: David Chase <drchase@google.com>
2019-04-02 16:34:03 +00:00

262 lines
5.3 KiB
Go

// errorcheck -0 -m -l
// Copyright 2015 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.
// Test escape analysis for interface conversions.
package escape
var sink interface{}
type M interface {
M()
}
func mescapes(m M) { // ERROR "leaking param: m"
sink = m // ERROR "m escapes to heap"
}
func mdoesnotescape(m M) { // ERROR "m does not escape"
}
// Tests for type stored directly in iface and with value receiver method.
type M0 struct {
p *int
}
func (M0) M() {
}
func efaceEscape0() {
{
i := 0
v := M0{&i}
var x M = v // ERROR "v does not escape"
_ = x
}
{
i := 0 // ERROR "moved to heap: i"
v := M0{&i}
var x M = v // ERROR "v escapes to heap"
sink = x // ERROR "x escapes to heap"
}
{
i := 0
v := M0{&i}
var x M = v // ERROR "v does not escape"
v1 := x.(M0)
_ = v1
}
{
i := 0 // ERROR "moved to heap: i"
v := M0{&i}
// BAD: v does not escape to heap here
var x M = v // ERROR "v escapes to heap"
v1 := x.(M0)
sink = v1 // ERROR "v1 escapes to heap"
}
{
i := 0 // ERROR "moved to heap: i"
v := M0{&i}
// BAD: v does not escape to heap here
var x M = v // ERROR "v escapes to heap"
x.M()
}
{
i := 0 // ERROR "moved to heap: i"
v := M0{&i}
var x M = v // ERROR "v escapes to heap"
mescapes(x)
}
{
i := 0
v := M0{&i}
var x M = v // ERROR "v does not escape"
mdoesnotescape(x)
}
}
// Tests for type stored indirectly in iface and with value receiver method.
type M1 struct {
p *int
x int
}
func (M1) M() {
}
func efaceEscape1() {
{
i := 0
v := M1{&i, 0}
var x M = v // ERROR "v does not escape"
_ = x
}
{
i := 0 // ERROR "moved to heap: i"
v := M1{&i, 0}
var x M = v // ERROR "v escapes to heap"
sink = x // ERROR "x escapes to heap"
}
{
i := 0
v := M1{&i, 0}
var x M = v // ERROR "v does not escape"
v1 := x.(M1)
_ = v1
}
{
i := 0 // ERROR "moved to heap: i"
v := M1{&i, 0}
// BAD: v does not escape to heap here
var x M = v // ERROR "v escapes to heap"
v1 := x.(M1)
sink = v1 // ERROR "v1 escapes to heap"
}
{
i := 0 // ERROR "moved to heap: i"
v := M1{&i, 0}
// BAD: v does not escape to heap here
var x M = v // ERROR "v escapes to heap"
x.M()
}
{
i := 0 // ERROR "moved to heap: i"
v := M1{&i, 0}
var x M = v // ERROR "v escapes to heap"
mescapes(x)
}
{
i := 0
v := M1{&i, 0}
var x M = v // ERROR "v does not escape"
mdoesnotescape(x)
}
}
// Tests for type stored directly in iface and with pointer receiver method.
type M2 struct {
p *int
}
func (*M2) M() {
}
func efaceEscape2() {
{
i := 0
v := &M2{&i} // ERROR "&M2 literal does not escape"
var x M = v // ERROR "v does not escape"
_ = x
}
{
i := 0 // ERROR "moved to heap: i"
v := &M2{&i} // ERROR "&M2 literal escapes to heap"
var x M = v // ERROR "v escapes to heap"
sink = x // ERROR "x escapes to heap"
}
{
i := 0
v := &M2{&i} // ERROR "&M2 literal does not escape"
var x M = v // ERROR "v does not escape"
v1 := x.(*M2)
_ = v1
}
{
i := 0 // ERROR "moved to heap: i"
v := &M2{&i} // ERROR "&M2 literal escapes to heap"
// BAD: v does not escape to heap here
var x M = v // ERROR "v escapes to heap"
v1 := x.(*M2)
sink = v1 // ERROR "v1 escapes to heap"
}
{
i := 0 // ERROR "moved to heap: i"
v := &M2{&i} // ERROR "&M2 literal does not escape"
// BAD: v does not escape to heap here
var x M = v // ERROR "v does not escape"
v1 := x.(*M2)
sink = *v1 // ERROR "v1 escapes to heap"
}
{
i := 0 // ERROR "moved to heap: i"
v := &M2{&i} // ERROR "&M2 literal does not escape"
// BAD: v does not escape to heap here
var x M = v // ERROR "v does not escape"
v1, ok := x.(*M2)
sink = *v1 // ERROR "v1 escapes to heap"
_ = ok
}
{
i := 0 // ERROR "moved to heap: i"
v := &M2{&i} // ERROR "&M2 literal escapes to heap"
// BAD: v does not escape to heap here
var x M = v // ERROR "v escapes to heap"
x.M()
}
{
i := 0 // ERROR "moved to heap: i"
v := &M2{&i} // ERROR "&M2 literal escapes to heap"
var x M = v // ERROR "v escapes to heap"
mescapes(x)
}
{
i := 0
v := &M2{&i} // ERROR "&M2 literal does not escape"
var x M = v // ERROR "v does not escape"
mdoesnotescape(x)
}
}
type T1 struct {
p *int
}
type T2 struct {
T1 T1
}
func dotTypeEscape() *T2 { // #11931
var x interface{}
x = &T1{p: new(int)} // ERROR "new\(int\) escapes to heap" "&T1 literal does not escape"
return &T2{
T1: *(x.(*T1)), // ERROR "&T2 literal escapes to heap"
}
}
func dotTypeEscape2() { // #13805, #15796
{
i := 0
j := 0
var v int
var ok bool
var x interface{} = i // ERROR "i does not escape"
var y interface{} = j // ERROR "j does not escape"
*(&v) = x.(int)
*(&v), *(&ok) = y.(int)
}
{
i := 0
j := 0
var ok bool
var x interface{} = i // ERROR "i does not escape"
var y interface{} = j // ERROR "j does not escape"
sink = x.(int) // ERROR "x.\(int\) escapes to heap"
sink, *(&ok) = y.(int)
}
{
i := 0 // ERROR "moved to heap: i"
j := 0 // ERROR "moved to heap: j"
var ok bool
var x interface{} = &i // ERROR "&i escapes to heap"
var y interface{} = &j // ERROR "&j escapes to heap"
sink = x.(*int) // ERROR "x.\(\*int\) escapes to heap"
sink, *(&ok) = y.(*int)
}
}