[dev.ssa] cmd/compile/internal/ssa: implement OCFUNC

Change-Id: Ieb9cddf8876bf8cd5ee1705d9210d22c3959e8cc
Reviewed-on: https://go-review.googlesource.com/14329
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Todd Neal <todd@tneal.org>
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 386420f..4fe8ba8 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -1203,6 +1203,9 @@
 
 	s.stmtList(n.Ninit)
 	switch n.Op {
+	case OCFUNC:
+		aux := &ssa.ExternSymbol{n.Type, n.Left.Sym}
+		return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
 	case ONAME:
 		if n.Class == PFUNC {
 			// "value" of a function is the address of the function's closure
@@ -1296,16 +1299,17 @@
 	case OCONVNOP:
 		to := n.Type
 		from := n.Left.Type
-		if to.Etype == TFUNC {
-			s.Unimplementedf("CONVNOP closure")
-			return nil
-		}
 
 		// Assume everything will work out, so set up our return value.
 		// Anything interesting that happens from here is a fatal.
 		x := s.expr(n.Left)
 		v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
 
+		// CONVNOP closure
+		if to.Etype == TFUNC && from.IsPtr() {
+			return v
+		}
+
 		// named <--> unnamed type or typed <--> untyped const
 		if from.Etype == to.Etype {
 			return v
diff --git a/src/cmd/compile/internal/gc/ssa_test.go b/src/cmd/compile/internal/gc/ssa_test.go
index 0bce902..feaea8b 100644
--- a/src/cmd/compile/internal/gc/ssa_test.go
+++ b/src/cmd/compile/internal/gc/ssa_test.go
@@ -78,3 +78,6 @@
 func TestString(t *testing.T) { runTest(t, "string_ssa.go") }
 
 func TestDeferNoReturn(t *testing.T) { buildTest(t, "deferNoReturn_ssa.go") }
+
+// TestClosure tests closure related behavior.
+func TestClosure(t *testing.T) { runTest(t, "closure_ssa.go") }
diff --git a/src/cmd/compile/internal/gc/testdata/closure_ssa.go b/src/cmd/compile/internal/gc/testdata/closure_ssa.go
new file mode 100644
index 0000000..ac1e51a
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/closure_ssa.go
@@ -0,0 +1,39 @@
+// Copyright 2015 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.
+
+// map_ssa.go tests map operations.
+package main
+
+import "fmt"
+
+var failed = false
+
+func testCFunc_ssa() int {
+	switch { // prevent inlining
+	}
+	a := 0
+	b := func() {
+		switch {
+		}
+		a++
+	}
+	b()
+	b()
+	return a
+}
+
+func testCFunc() {
+	if want, got := 2, testCFunc_ssa(); got != want {
+		fmt.Printf("expected %d, got %d", want, got)
+		failed = true
+	}
+}
+
+func main() {
+	testCFunc()
+
+	if failed {
+		panic("failed")
+	}
+}