cmd/internal/gc: extend escape analysis to pointers in slices

Modified esc.go to allow slice literals (before append)
to be non-escaping.  Modified tests to account for changes
in escape behavior and to also test the two cases that
were previously not tested.

Also minor cleanups to debug-printing within esc.go

Allocation stats for running compiler
( cd src/html/template;
  for i in {1..5} ; do
     go tool 6g -memprofile=testzz.${i}.prof  -memprofilerate=1 *.go ;
     go tool pprof -alloc_objects -text  testzz.${i}.prof ;
     done ; )
before about 86k allocations
after  about 83k allocations

Fixes #8972

Change-Id: Ib61dd70dc74adb40d6f6fdda6eaa4bf7d83481de
Reviewed-on: https://go-review.googlesource.com/10118
Reviewed-by: Russ Cox <rsc@golang.org>
diff --git a/test/escape2.go b/test/escape2.go
index cc71471..dfc37ed 100644
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -787,7 +787,7 @@
 }
 
 // does not leak m
-func foo94(m map[*int]*int, b bool) *int { // ERROR "foo94 m does not escape$"
+func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1"
 	for k, v := range m {
 		if b {
 			return k
@@ -802,8 +802,8 @@
 	m[x] = x
 }
 
-// does not leak m
-func foo96(m []*int) *int { // ERROR "foo96 m does not escape$"
+// does not leak m but does leak content
+func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
 	return m[0]
 }
 
@@ -823,7 +823,7 @@
 }
 
 // does not leak m
-func foo100(m []*int) *int { // ERROR "foo100 m does not escape$"
+func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
 	for _, v := range m {
 		return v
 	}
@@ -863,8 +863,8 @@
 	copy(y, x)
 }
 
-// does not leak x
-func foo105(x []*int) { // ERROR "foo105 x does not escape$"
+// does not leak x but does leak content
+func foo105(x []*int) { // ERROR "leaking param content: x"
 	_ = append(y, x...)
 }
 
@@ -894,7 +894,7 @@
 	return m[nil]
 }
 
-func foo111(x *int) *int { // ERROR "leaking param: x$"
+func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0"
 	m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$"
 	return m[0]
 }
diff --git a/test/escape2n.go b/test/escape2n.go
index bf8c534..56f05eb 100644
--- a/test/escape2n.go
+++ b/test/escape2n.go
@@ -787,7 +787,7 @@
 }
 
 // does not leak m
-func foo94(m map[*int]*int, b bool) *int { // ERROR "foo94 m does not escape$"
+func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1"
 	for k, v := range m {
 		if b {
 			return k
@@ -802,8 +802,8 @@
 	m[x] = x
 }
 
-// does not leak m
-func foo96(m []*int) *int { // ERROR "foo96 m does not escape$"
+// does not leak m but does leak content
+func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
 	return m[0]
 }
 
@@ -823,7 +823,7 @@
 }
 
 // does not leak m
-func foo100(m []*int) *int { // ERROR "foo100 m does not escape$"
+func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
 	for _, v := range m {
 		return v
 	}
@@ -863,8 +863,8 @@
 	copy(y, x)
 }
 
-// does not leak x
-func foo105(x []*int) { // ERROR "foo105 x does not escape$"
+// does not leak x but does leak content
+func foo105(x []*int) { // ERROR "leaking param content: x"
 	_ = append(y, x...)
 }
 
@@ -894,7 +894,7 @@
 	return m[nil]
 }
 
-func foo111(x *int) *int { // ERROR "leaking param: x$"
+func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0"
 	m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$"
 	return m[0]
 }
diff --git a/test/escape_slice.go b/test/escape_slice.go
index 9315e27..0b65997 100644
--- a/test/escape_slice.go
+++ b/test/escape_slice.go
@@ -8,6 +8,11 @@
 
 package escape
 
+import (
+	"os"
+	"strings"
+)
+
 var sink interface{}
 
 func slice0() {
@@ -71,9 +76,8 @@
 }
 
 func slice8() {
-	// BAD: i should not escape here
-	i := 0          // ERROR "moved to heap: i"
-	s := []*int{&i} // ERROR "&i escapes to heap" "literal does not escape"
+	i := 0
+	s := []*int{&i} // ERROR "&i does not escape" "literal does not escape"
 	_ = s
 }
 
@@ -88,3 +92,74 @@
 	s := []*int{&i} // ERROR "&i escapes to heap" "literal escapes to heap"
 	return s
 }
+
+func envForDir(dir string) []string { // ERROR "dir does not escape"
+	env := os.Environ()
+	return mergeEnvLists([]string{"PWD=" + dir}, env) // ERROR ".PWD=. \+ dir escapes to heap" "\[\]string literal does not escape"
+}
+
+func mergeEnvLists(in, out []string) []string { // ERROR "leaking param content: in" "leaking param content: out" "leaking param: out to result ~r2 level=0"
+NextVar:
+	for _, inkv := range in {
+		k := strings.SplitAfterN(inkv, "=", 2)[0]
+		for i, outkv := range out {
+			if strings.HasPrefix(outkv, k) {
+				out[i] = inkv
+				continue NextVar
+			}
+		}
+		out = append(out, inkv)
+	}
+	return out
+}
+
+const (
+	IPv4len = 4
+	IPv6len = 16
+)
+
+var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}
+
+func IPv4(a, b, c, d byte) IP {
+	p := make(IP, IPv6len) // ERROR "make\(IP, IPv6len\) escapes to heap"
+	copy(p, v4InV6Prefix)
+	p[12] = a
+	p[13] = b
+	p[14] = c
+	p[15] = d
+	return p
+}
+
+type IP []byte
+
+type IPAddr struct {
+	IP   IP
+	Zone string // IPv6 scoped addressing zone
+}
+
+type resolveIPAddrTest struct {
+	network       string
+	litAddrOrName string
+	addr          *IPAddr
+	err           error
+}
+
+var resolveIPAddrTests = []resolveIPAddrTest{
+	{"ip", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
+	{"ip4", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
+	{"ip4:icmp", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
+}
+
+func setupTestData() {
+	resolveIPAddrTests = append(resolveIPAddrTests,
+		[]resolveIPAddrTest{ // ERROR "\[\]resolveIPAddrTest literal does not escape"
+			{"ip",
+				"localhost",
+				&IPAddr{IP: IPv4(127, 0, 0, 1)}, // ERROR "&IPAddr literal escapes to heap"
+				nil},
+			{"ip4",
+				"localhost",
+				&IPAddr{IP: IPv4(127, 0, 0, 1)}, // ERROR "&IPAddr literal escapes to heap"
+				nil},
+		}...)
+}