cmd/compile: handle OCLOSURE/OCALLPART in mustHeapAlloc check

Currently, generated struct wrapper for closure is not handled in
mustHeapAlloc. That causes compiler crashes when the wrapper struct
is too large for stack, and must be heap allocated instead.

Fixes #39292

Change-Id: I14c1e591681d9d92317bb2396d6cf5207aa93e08
Reviewed-on: https://go-review.googlesource.com/c/go/+/244917
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go
index 3bb7bb9..04fb7d5 100644
--- a/src/cmd/compile/internal/gc/closure.go
+++ b/src/cmd/compile/internal/gc/closure.go
@@ -526,7 +526,7 @@
 	// Create closure in the form of a composite literal.
 	// For x.M with receiver (x) type T, the generated code looks like:
 	//
-	//	clos = &struct{F uintptr; R T}{M.T·f, x}
+	//	clos = &struct{F uintptr; R T}{T.M·f, x}
 	//
 	// Like walkclosure above.
 
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index f3e9ab7..6289537 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -187,6 +187,13 @@
 		return true
 	}
 
+	if n.Op == OCLOSURE && closureType(n).Size() >= maxImplicitStackVarSize {
+		return true
+	}
+	if n.Op == OCALLPART && partialCallType(n).Size() >= maxImplicitStackVarSize {
+		return true
+	}
+
 	if n.Op == OMAKESLICE && !isSmallMakeSlice(n) {
 		return true
 	}
diff --git a/test/fixedbugs/issue39292.go b/test/fixedbugs/issue39292.go
new file mode 100644
index 0000000..5d6595c
--- /dev/null
+++ b/test/fixedbugs/issue39292.go
@@ -0,0 +1,29 @@
+// errorcheck -0 -m -l
+
+// Copyright 2020 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.
+
+package p
+
+type t [10000]*int
+
+func (t) f() {
+}
+
+func x() {
+	x := t{}.f // ERROR "t literal.f escapes to heap"
+	x()
+}
+
+func y() {
+	var i int       // ERROR "moved to heap: i"
+	y := (&t{&i}).f // ERROR "\(&t literal\).f escapes to heap" "&t literal escapes to heap"
+	y()
+}
+
+func z() {
+	var i int    // ERROR "moved to heap: i"
+	z := t{&i}.f // ERROR "t literal.f escapes to heap"
+	z()
+}