1
0
mirror of https://github.com/golang/go synced 2024-11-27 05:31:31 -07:00
go/test/escape5.go
Russ Cox a069cf048d cmd/gc: distinguish unnamed vs blank-named return variables better
Before, an unnamed return value turned into an ONAME node n with n->sym
named ~anon%d, and n->orig == n.

A blank-named return value turned into an ONAME node n with n->sym
named ~anon%d but n->orig == the original blank n. Code generation and
printing uses n->orig, so that this node formatted as _.

But some code does not use n->orig. In particular the liveness code does
not know about the n->orig convention and so mishandles blank identifiers.
It is possible to fix but seemed better to avoid the confusion entirely.

Now the first kind of node is named ~r%d and the second ~b%d; both have
n->orig == n, so that it doesn't matter whether code uses n or n->orig.

After this change the ->orig field is only used for other kinds of expressions,
not for ONAME nodes.

This requires distinguishing ~b from ~r names in a few places that care.
It fixes a liveness analysis bug without actually changing the liveness code.

TBR=ken2
CC=golang-codereviews
https://golang.org/cl/63630043
2014-02-13 20:59:39 -05:00

152 lines
3.4 KiB
Go

// errorcheck -0 -m -l
// Copyright 2012 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, using compiler diagnostic flags, that the escape analysis is working.
// Compiles but does not run. Inlining is disabled.
package foo
func noleak(p *int) int { // ERROR "p does not escape"
return *p
}
func leaktoret(p *int) *int { // ERROR "leaking param: p to result"
return p
}
func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: p to result ~r2"
return p, p
}
func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r2" "leaking param: q to result ~r3"
return p, q
}
func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2"
return leaktoret22(q, p)
}
func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2"
r, s := leaktoret22(q, p)
return r, s
}
func leaktoret22d(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r"
r, s = leaktoret22(q, p)
return
}
func leaktoret22e(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r"
r, s = leaktoret22(q, p)
return r, s
}
func leaktoret22f(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r"
rr, ss := leaktoret22(q, p)
return rr, ss
}
var gp *int
func leaktosink(p *int) *int { // ERROR "leaking param: p"
gp = p
return p
}
func f1() {
var x int
p := noleak(&x) // ERROR "&x does not escape"
_ = p
}
func f2() {
var x int
p := leaktoret(&x) // ERROR "&x does not escape"
_ = p
}
func f3() {
var x int // ERROR "moved to heap: x"
p := leaktoret(&x) // ERROR "&x escapes to heap"
gp = p
}
func f4() {
var x int // ERROR "moved to heap: x"
p, q := leaktoret2(&x) // ERROR "&x escapes to heap"
gp = p
gp = q
}
func f5() {
var x int
leaktoret22(leaktoret2(&x)) // ERROR "&x does not escape"
}
func f6() {
var x int // ERROR "moved to heap: x"
px1, px2 := leaktoret22(leaktoret2(&x)) // ERROR "&x escapes to heap"
gp = px1
_ = px2
}
type T struct{ x int }
func (t *T) Foo(u int) (*T, bool) { // ERROR "leaking param: t to result"
t.x += u
return t, true
}
func f7() *T {
r, _ := new(T).Foo(42) // ERROR "new.T. escapes to heap"
return r
}
func leakrecursive1(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q"
return leakrecursive2(q, p)
}
func leakrecursive2(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q"
if *p > *q {
return leakrecursive1(q, p)
}
// without this, leakrecursive? are safe for p and q, b/c in fact their graph does not have leaking edges.
return p, q
}
var global interface{}
type T1 struct {
X *int
}
type T2 struct {
Y *T1
}
func f8(p *T1) (k T2) { // ERROR "leaking param: p to result k" "leaking param: p"
if p == nil {
k = T2{}
return
}
global = p // should make p leak always
return T2{p}
}
func f9() {
var j T1 // ERROR "moved to heap: j"
f8(&j) // ERROR "&j escapes to heap"
}
func f10() {
// These don't escape but are too big for the stack
var x [1<<30]byte // ERROR "moved to heap: x"
var y = make([]byte, 1<<30) // ERROR "does not escape"
_ = x[0] + y[0]
}