cmd/gc: preserve side effects during inlining of function with _ argument

Fixes #3593.

R=ken2
CC=golang-dev, lvd
https://golang.org/cl/6305061
This commit is contained in:
Russ Cox 2012-06-07 01:54:07 -04:00
parent 09b736a2ab
commit ee5f59ab4f
2 changed files with 57 additions and 22 deletions

View file

@ -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)

36
test/fixedbugs/bug441.go Normal file
View file

@ -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
}