mirror of
https://github.com/golang/go
synced 2024-09-30 05:07:17 +00:00
[release-branch.go1.3] cmd/gc: two escape analysis fixes
««« CL 108860043 / f153208c0a0e cmd/gc: fix escape analysis for &x inside switch x := v.(type) The analysis for &x was using the loop depth on x set during x's declaration. A type switch creates a list of implicit declarations that were not getting initialized with loop depths. Fixes #8176. LGTM=iant R=iant CC=golang-codereviews https://golang.org/cl/108860043 »»» ««« CL 108870044 / 331dbd4a6334 cmd/gc: fix &result escaping into result There is a hierarchy of location defined by loop depth: -1 = the heap 0 = function results 1 = local variables (and parameters) 2 = local variable declared inside a loop 3 = local variable declared inside a loop inside a loop etc In general if an address from loopdepth n is assigned to something in loop depth m < n, that indicates an extended lifetime of some form that requires a heap allocation. Function results can be local variables too, though, and so they don't actually fit into the hierarchy very well. Treat the address of a function result as level 1 so that if it is written back into a result, the address is treated as escaping. Fixes issue 8185 . LGTM=iant R=iant CC=golang-codereviews https://golang.org/cl/108870044 »»» LGTM=r R=golang-codereviews, r CC=bradfitz, golang-codereviews, iant https://golang.org/cl/107930044
This commit is contained in:
parent
16367614fb
commit
8ef4135731
|
@ -442,6 +442,18 @@ esc(EscState *e, Node *n, Node *up)
|
|||
if(n->op == OFOR || n->op == ORANGE)
|
||||
e->loopdepth++;
|
||||
|
||||
// type switch variables have no ODCL.
|
||||
// process type switch as declaration.
|
||||
// must happen before processing of switch body,
|
||||
// so before recursion.
|
||||
if(n->op == OSWITCH && n->ntest && n->ntest->op == OTYPESW) {
|
||||
for(ll=n->list; ll; ll=ll->next) { // cases
|
||||
// ll->n->nname is the variable per case
|
||||
if(ll->n->nname)
|
||||
ll->n->nname->escloopdepth = e->loopdepth;
|
||||
}
|
||||
}
|
||||
|
||||
esc(e, n->left, n);
|
||||
esc(e, n->right, n);
|
||||
esc(e, n->ntest, n);
|
||||
|
@ -658,13 +670,24 @@ esc(EscState *e, Node *n, Node *up)
|
|||
// current loop depth is an upper bound on actual loop depth
|
||||
// of addressed value.
|
||||
n->escloopdepth = e->loopdepth;
|
||||
// for &x, use loop depth of x.
|
||||
// for &x, use loop depth of x if known.
|
||||
// it should always be known, but if not, be conservative
|
||||
// and keep the current loop depth.
|
||||
if(n->left->op == ONAME) {
|
||||
switch(n->left->class) {
|
||||
case PAUTO:
|
||||
if(n->left->escloopdepth != 0)
|
||||
n->escloopdepth = n->left->escloopdepth;
|
||||
break;
|
||||
case PPARAM:
|
||||
case PPARAMOUT:
|
||||
n->escloopdepth = n->left->escloopdepth;
|
||||
// PPARAM is loop depth 1 always.
|
||||
// PPARAMOUT is loop depth 0 for writes
|
||||
// but considered loop depth 1 for address-of,
|
||||
// so that writing the address of one result
|
||||
// to another (or the same) result makes the
|
||||
// first result move to the heap.
|
||||
n->escloopdepth = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1468,3 +1468,25 @@ func foo152() {
|
|||
v := NewV(u)
|
||||
println(v)
|
||||
}
|
||||
|
||||
// issue 8176 - &x in type switch body not marked as escaping
|
||||
|
||||
func foo153(v interface{}) *int { // ERROR "leaking param: v"
|
||||
switch x := v.(type) {
|
||||
case int: // ERROR "moved to heap: x"
|
||||
return &x // ERROR "&x escapes to heap"
|
||||
}
|
||||
panic(0)
|
||||
}
|
||||
|
||||
// issue 8185 - &result escaping into result
|
||||
|
||||
func f() (x int, y *int) { // ERROR "moved to heap: x"
|
||||
y = &x // ERROR "&x escapes to heap"
|
||||
return
|
||||
}
|
||||
|
||||
func g() (x interface{}) { // ERROR "moved to heap: x"
|
||||
x = &x // ERROR "&x escapes to heap"
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue