mirror of https://github.com/golang/go.git
cmd/gc: fix escape analysis of method values
R=ken2 CC=golang-dev https://golang.org/cl/7518050
This commit is contained in:
parent
0ad265d48f
commit
38e9b0773d
|
|
@ -270,8 +270,9 @@ typecheckpartialcall(Node *fn, Node *sym)
|
||||||
|
|
||||||
// Create top-level function.
|
// Create top-level function.
|
||||||
fn->nname = makepartialcall(fn, fn->type, sym);
|
fn->nname = makepartialcall(fn, fn->type, sym);
|
||||||
|
fn->right = sym;
|
||||||
fn->op = OCALLPART;
|
fn->op = OCALLPART;
|
||||||
fn->type = fn->right->type;
|
fn->type = fn->nname->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Node*
|
static Node*
|
||||||
|
|
|
||||||
|
|
@ -596,6 +596,14 @@ esc(EscState *e, Node *n)
|
||||||
// Contents make it to memory, lose track.
|
// Contents make it to memory, lose track.
|
||||||
escassign(e, &e->theSink, n->left);
|
escassign(e, &e->theSink, n->left);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OCALLPART:
|
||||||
|
n->esc = EscNone; // until proven otherwise
|
||||||
|
e->noesc = list(e->noesc, n);
|
||||||
|
n->escloopdepth = e->loopdepth;
|
||||||
|
// Contents make it to memory, lose track.
|
||||||
|
escassign(e, &e->theSink, n->left);
|
||||||
|
break;
|
||||||
|
|
||||||
case OMAPLIT:
|
case OMAPLIT:
|
||||||
n->esc = EscNone; // until proven otherwise
|
n->esc = EscNone; // until proven otherwise
|
||||||
|
|
@ -667,6 +675,7 @@ escassign(EscState *e, Node *dst, Node *src)
|
||||||
case OCONVNOP:
|
case OCONVNOP:
|
||||||
case OMAPLIT:
|
case OMAPLIT:
|
||||||
case OSTRUCTLIT:
|
case OSTRUCTLIT:
|
||||||
|
case OCALLPART:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ONAME:
|
case ONAME:
|
||||||
|
|
@ -713,6 +722,7 @@ escassign(EscState *e, Node *dst, Node *src)
|
||||||
case OMAKESLICE:
|
case OMAKESLICE:
|
||||||
case ONEW:
|
case ONEW:
|
||||||
case OCLOSURE:
|
case OCLOSURE:
|
||||||
|
case OCALLPART:
|
||||||
escflows(e, dst, src);
|
escflows(e, dst, src);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -1073,6 +1083,7 @@ escwalk(EscState *e, int level, Node *dst, Node *src)
|
||||||
case OMAPLIT:
|
case OMAPLIT:
|
||||||
case ONEW:
|
case ONEW:
|
||||||
case OCLOSURE:
|
case OCLOSURE:
|
||||||
|
case OCALLPART:
|
||||||
if(leaks) {
|
if(leaks) {
|
||||||
src->esc = EscHeap;
|
src->esc = EscHeap;
|
||||||
if(debug['m'])
|
if(debug['m'])
|
||||||
|
|
|
||||||
|
|
@ -1022,6 +1022,7 @@ static int opprec[] = {
|
||||||
[ODOTTYPE] = 8,
|
[ODOTTYPE] = 8,
|
||||||
[ODOT] = 8,
|
[ODOT] = 8,
|
||||||
[OXDOT] = 8,
|
[OXDOT] = 8,
|
||||||
|
[OCALLPART] = 8,
|
||||||
|
|
||||||
[OPLUS] = 7,
|
[OPLUS] = 7,
|
||||||
[ONOT] = 7,
|
[ONOT] = 7,
|
||||||
|
|
@ -1269,9 +1270,10 @@ exprfmt(Fmt *f, Node *n, int prec)
|
||||||
case ODOTPTR:
|
case ODOTPTR:
|
||||||
case ODOTINTER:
|
case ODOTINTER:
|
||||||
case ODOTMETH:
|
case ODOTMETH:
|
||||||
|
case OCALLPART:
|
||||||
exprfmt(f, n->left, nprec);
|
exprfmt(f, n->left, nprec);
|
||||||
if(n->right == N || n->right->sym == S)
|
if(n->right == N || n->right->sym == S)
|
||||||
fmtstrcpy(f, ".<nil>");
|
return fmtstrcpy(f, ".<nil>");
|
||||||
return fmtprint(f, ".%hhS", n->right->sym);
|
return fmtprint(f, ".%hhS", n->right->sym);
|
||||||
|
|
||||||
case ODOTTYPE:
|
case ODOTTYPE:
|
||||||
|
|
|
||||||
|
|
@ -1303,3 +1303,25 @@ func G() {
|
||||||
var buf4 [10]byte // ERROR "moved to heap: buf4"
|
var buf4 [10]byte // ERROR "moved to heap: buf4"
|
||||||
F4(buf4[:]) // ERROR "buf4 escapes to heap"
|
F4(buf4[:]) // ERROR "buf4 escapes to heap"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Tm struct {
|
||||||
|
x int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tm) M() { // ERROR "t does not escape"
|
||||||
|
}
|
||||||
|
|
||||||
|
func foo141() {
|
||||||
|
var f func()
|
||||||
|
|
||||||
|
t := new(Tm) // ERROR "escapes to heap"
|
||||||
|
f = t.M // ERROR "t.M does not escape"
|
||||||
|
_ = f
|
||||||
|
}
|
||||||
|
|
||||||
|
var gf func()
|
||||||
|
|
||||||
|
func foo142() {
|
||||||
|
t := new(Tm) // ERROR "escapes to heap"
|
||||||
|
gf = t.M // ERROR "t.M escapes to heap"
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
// run
|
||||||
|
|
||||||
|
// Copyright 2013 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.
|
||||||
|
|
||||||
|
// Bug in method values: escape analysis was off.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
var called = false
|
||||||
|
|
||||||
|
type T struct {
|
||||||
|
once sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *T) M() {
|
||||||
|
called = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var t T
|
||||||
|
t.once.Do(t.M)
|
||||||
|
if !called {
|
||||||
|
panic("not called")
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue