From ee5f59ab4feafd987972a096d5a5c315e753f358 Mon Sep 17 00:00:00 2001
From: Russ Cox <rsc@golang.org>
Date: Thu, 7 Jun 2012 01:54:07 -0400
Subject: [PATCH] cmd/gc: preserve side effects during inlining of function
 with _ argument

Fixes #3593.

R=ken2
CC=golang-dev, lvd
https://golang.org/cl/6305061
---
 src/cmd/gc/inl.c         | 43 ++++++++++++++++++++--------------------
 test/fixedbugs/bug441.go | 36 +++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+), 22 deletions(-)
 create mode 100644 test/fixedbugs/bug441.go

diff --git a/src/cmd/gc/inl.c b/src/cmd/gc/inl.c
index 45a71495d4..6dda362e7e 100644
--- a/src/cmd/gc/inl.c
+++ b/src/cmd/gc/inl.c
@@ -506,6 +506,19 @@ mkinlcall(Node **np, Node *fn)
 	mkinlcall1(np, fn);
 	safemode = save_safemode;
 }
+
+static Node*
+tinlvar(Type *t)
+{
+	if(t->nname && !isblank(t->nname)) {
+		if(!t->nname->inlvar)
+			fatal("missing inlvar for %N\n", t->nname);
+		return t->nname->inlvar;
+	}
+	typecheck(&nblank, Erv | Easgn);
+	return nblank;
+}
+
 // if *np is a call, and fn is a function with an inlinable body, substitute *np with an OINLCALL.
 // On return ninit has the parameter assignments, the nbody is the
 // inlined function body and list, rlist contain the input, output
@@ -579,15 +592,12 @@ mkinlcall1(Node **np, Node *fn)
 				fatal("method call without receiver: %+N", n);
 			if(t == T)
 				fatal("method call unknown receiver type: %+N", n);
-			if(t->nname != N && !isblank(t->nname))
-				as = nod(OAS, t->nname->inlvar, n->left->left);
-			else
-				as = nod(OAS, temp(t->type), n->left->left);
+			as = nod(OAS, tinlvar(t), n->left->left);
 		} else {  // non-method call to method
-			if (!n->list)
+			if(!n->list)
 				fatal("non-method call to method without first arg: %+N", n);
-			if(t != T && t->nname != N && !isblank(t->nname))
-				as = nod(OAS, t->nname->inlvar, n->list->n);
+			if(t != T)
+				as = nod(OAS, tinlvar(t), n->list->n);
 		}
 
 		if(as != N) {
@@ -601,27 +611,16 @@ mkinlcall1(Node **np, Node *fn)
 		// TODO check that n->list->n is a call?
 		// TODO: non-method call to T.meth(f()) where f returns t, args...
 		as->rlist = n->list;
-		for(t = getinargx(fn->type)->type; t; t=t->down) {
-			if(t->nname && !isblank(t->nname)) {
-				if(!t->nname->inlvar)
-					fatal("missing inlvar for %N\n", t->nname);
-				as->list = list(as->list, t->nname->inlvar);
-			} else {
-				as->list = list(as->list, temp(t->type));
-			}
-		}		
+		for(t = getinargx(fn->type)->type; t; t=t->down)
+			as->list = list(as->list, tinlvar(t));		
 	} else {
 		ll = n->list;
 		if(fn->type->thistuple && n->left->op != ODOTMETH) // non method call to method
 			ll=ll->next;  // was handled above in if(thistuple)
 
 		for(t = getinargx(fn->type)->type; t && ll; t=t->down) {
-			if(t->nname && !isblank(t->nname)) {
-				if(!t->nname->inlvar)
-					fatal("missing inlvar for %N\n", t->nname);
-				as->list = list(as->list, t->nname->inlvar);
-				as->rlist = list(as->rlist, ll->n);
-			}
+			as->list = list(as->list, tinlvar(t));
+			as->rlist = list(as->rlist, ll->n);
 			ll=ll->next;
 		}
 		if(ll || t)
diff --git a/test/fixedbugs/bug441.go b/test/fixedbugs/bug441.go
new file mode 100644
index 0000000000..8562bfeef8
--- /dev/null
+++ b/test/fixedbugs/bug441.go
@@ -0,0 +1,36 @@
+// run
+
+// Copyright 2012 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.
+
+// Was discarding function calls made for arguments named _
+// in inlined functions.  Issue 3593.
+
+package main
+
+var did int
+
+func main() {
+	foo(side())
+	foo2(side(), side())
+	foo3(side(), side())
+	T.m1(T(side()))
+	T(1).m2(side())
+	const want = 7
+	if did != want {
+		println("BUG: missing", want-did, "calls")
+	}
+}
+
+func foo(_ int) {}
+func foo2(_, _ int) {}
+func foo3(int, int) {}
+type T int
+func (_ T) m1() {}
+func (t T) m2(_ int) {}
+
+func side() int {
+	did++
+	return 1
+}
-- 
2.30.9