summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2012-11-07 15:15:21 -0500
committerRuss Cox <rsc@golang.org>2012-11-07 15:15:21 -0500
commitea061e1d879fe51ac8e4241dd57a482b8988d395 (patch)
tree59f8a9a78ece870e7fb9492e6f5ea234f6300719
parent01ec23cdef879dee887a4258959cbc2ef464a086 (diff)
downloadgo-ea061e1d879fe51ac8e4241dd57a482b8988d395.tar.gz
cmd/gc: fix escape analysis bug
The code assumed that the only choices were EscNone, EscScope, and EscHeap, so that it makes sense to set EscScope only if the current setting is EscNone. Now that we have the many variants of EscReturn, this logic is false, and it was causing important EscScopes to be ignored in favor of EscReturn. Fixes issue 4360. R=ken2 CC=golang-dev, lvd http://codereview.appspot.com/6816103
-rw-r--r--src/cmd/gc/esc.c4
-rw-r--r--src/cmd/gc/subr.c2
-rw-r--r--test/escape5.go25
3 files changed, 29 insertions, 2 deletions
diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c
index f789386bc..f067cc530 100644
--- a/src/cmd/gc/esc.c
+++ b/src/cmd/gc/esc.c
@@ -1005,8 +1005,8 @@ escwalk(EscState *e, int level, Node *dst, Node *src)
if((src->esc&EscMask) != EscReturn)
src->esc = EscReturn;
src->esc |= 1<<((dst->vargen-1) + EscBits);
+ goto recurse;
}
- goto recurse;
}
}
@@ -1014,7 +1014,7 @@ escwalk(EscState *e, int level, Node *dst, Node *src)
switch(src->op) {
case ONAME:
- if(src->class == PPARAM && leaks && src->esc == EscNone) {
+ if(src->class == PPARAM && leaks && src->esc != EscHeap) {
src->esc = EscScope;
if(debug['m'])
warnl(src->lineno, "leaking param: %hN", src);
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 142921153..71417bb0a 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -219,6 +219,8 @@ warnl(int line, char *fmt, ...)
va_start(arg, fmt);
adderr(line, fmt, arg);
va_end(arg);
+ if(debug['m'])
+ flusherrors();
}
void
diff --git a/test/escape5.go b/test/escape5.go
index 22c324f90..6b327fe9e 100644
--- a/test/escape5.go
+++ b/test/escape5.go
@@ -117,3 +117,28 @@ func leakrecursive2(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaki
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"
+}