cmd/gc: improve escape analysis for &T{...}

Currently all PTRLIT element initializers escape. There is no reason for that.
This change links STRUCTLIT to PTRLIT; STRUCTLIT element initializers are
already linked to the STRUCTLIT. As the result, PTRLIT element initializers
escape when PTRLIT itself escapes.

Change-Id: I89ecd8677cbf81addcfd469cd2fd461c0e9bf7dd
Reviewed-on: https://go-review.googlesource.com/3031
Reviewed-by: Russ Cox <rsc@golang.org>
diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c
index 7c7095c..2fdbd99 100644
--- a/src/cmd/gc/esc.c
+++ b/src/cmd/gc/esc.c
@@ -615,15 +615,15 @@
 		for(ll=n->list; ll; ll=ll->next)
 			escassign(e, n, ll->n->right);
 		break;
-	
+
 	case OPTRLIT:
 		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);
+		// Link OSTRUCTLIT to OPTRLIT; if OPTRLIT escapes, OSTRUCTLIT elements do too.
+		escassign(e, n, n->left);
 		break;
-	
+
 	case OCALLPART:
 		n->esc = EscNone; // until proven otherwise
 		e->noesc = list(e->noesc, n);
@@ -730,6 +730,7 @@
 	case OCONVNOP:
 	case OMAPLIT:
 	case OSTRUCTLIT:
+	case OPTRLIT:
 	case OCALLPART:
 		break;
 
diff --git a/test/escape2.go b/test/escape2.go
index 6a46ce8..357ce4a 100644
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -1492,3 +1492,30 @@
 	x = &x // ERROR "&x escapes to heap"
 	return
 }
+
+var sink interface{}
+
+type Lit struct {
+	p *int
+}
+
+func ptrlitNoescape() {
+	// Both literal and element do not escape.
+	i := 0
+	x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i does not escape"
+	_ = x
+}
+
+func ptrlitNoEscape2() {
+	// Literal does not escape, but element does.
+	i := 0 // ERROR "moved to heap: i"
+	x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i escapes to heap"
+	sink = *x
+}
+
+func ptrlitEscape() {
+	// Both literal and element escape.
+	i := 0 // ERROR "moved to heap: i"
+	x := &Lit{&i} // ERROR "&Lit literal escapes to heap" "&i escapes to heap"
+	sink = x
+}
diff --git a/test/escape2n.go b/test/escape2n.go
index 002a78e..3e9bb70 100644
--- a/test/escape2n.go
+++ b/test/escape2n.go
@@ -1492,3 +1492,30 @@
 	x = &x // ERROR "&x escapes to heap"
 	return
 }
+
+var sink interface{}
+
+type Lit struct {
+	p *int
+}
+
+func ptrlitNoescape() {
+	// Both literal and element do not escape.
+	i := 0
+	x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i does not escape"
+	_ = x
+}
+
+func ptrlitNoEscape2() {
+	// Literal does not escape, but element does.
+	i := 0 // ERROR "moved to heap: i"
+	x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i escapes to heap"
+	sink = *x
+}
+
+func ptrlitEscape() {
+	// Both literal and element escape.
+	i := 0 // ERROR "moved to heap: i"
+	x := &Lit{&i} // ERROR "&Lit literal escapes to heap" "&i escapes to heap"
+	sink = x
+}