cmd/compile: fix miscompilation during inlining

When inlining a function call expression, it's possible that the
function callee subexpression has side effects that need to be
preserved. This used to not be an issue, because inlining wouldn't
recognize these as inlinable anyway. But golang.org/cl/266199 extended
the inlining logic to recognize more cases, but did not notice that
the actual inlining code was discarding side effects.

Issue identified by danscales@.

Fixes #42703.

Change-Id: I95f8fc076b6ca4e9362e80ec26dad9d87a5bc44a
Reviewed-on: https://go-review.googlesource.com/c/go/+/271219
Reviewed-by: Dan Scales <danscales@google.com>
Trust: Dan Scales <danscales@google.com>
Trust: Matthew Dempsky <mdempsky@google.com>
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index d49a094..4190569 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -963,6 +963,21 @@
 
 	ninit := n.Ninit
 
+	// For normal function calls, the function callee expression
+	// may contain side effects (e.g., added by addinit during
+	// inlconv2expr or inlconv2list). Make sure to preserve these,
+	// if necessary (#42703).
+	if n.Op == OCALLFUNC {
+		callee := n.Left
+		for callee.Op == OCONVNOP {
+			ninit.AppendNodes(&callee.Ninit)
+			callee = callee.Left
+		}
+		if callee.Op != ONAME && callee.Op != OCLOSURE {
+			Fatalf("unexpected callee expression: %v", callee)
+		}
+	}
+
 	// Make temp names to use instead of the originals.
 	inlvars := make(map[*Node]*Node)
 
diff --git a/test/fixedbugs/issue42703.go b/test/fixedbugs/issue42703.go
new file mode 100644
index 0000000..15f7a91
--- /dev/null
+++ b/test/fixedbugs/issue42703.go
@@ -0,0 +1,19 @@
+// run
+
+// 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 main
+
+var ok [2]bool
+
+func main() {
+	f()()
+	if !ok[0] || !ok[1] {
+		panic("FAIL")
+	}
+}
+
+func f() func() { ok[0] = true; return g }
+func g()        { ok[1] = true }