mirror of
https://github.com/golang/go
synced 2024-11-15 10:50:37 -07:00
[release-branch.go1] cmd/gc: preserve side effects during inlining of function with _ argument
««« backport 0ba8e27c7b87 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:
parent
dc0f7d6fde
commit
4bc9ddf82f
@ -506,6 +506,19 @@ mkinlcall(Node **np, Node *fn)
|
|||||||
mkinlcall1(np, fn);
|
mkinlcall1(np, fn);
|
||||||
safemode = save_safemode;
|
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.
|
// 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
|
// On return ninit has the parameter assignments, the nbody is the
|
||||||
// inlined function body and list, rlist contain the input, output
|
// 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);
|
fatal("method call without receiver: %+N", n);
|
||||||
if(t == T)
|
if(t == T)
|
||||||
fatal("method call unknown receiver type: %+N", n);
|
fatal("method call unknown receiver type: %+N", n);
|
||||||
if(t->nname != N && !isblank(t->nname))
|
as = nod(OAS, tinlvar(t), n->left->left);
|
||||||
as = nod(OAS, t->nname->inlvar, n->left->left);
|
|
||||||
else
|
|
||||||
as = nod(OAS, temp(t->type), n->left->left);
|
|
||||||
} else { // non-method call to method
|
} else { // non-method call to method
|
||||||
if (!n->list)
|
if(!n->list)
|
||||||
fatal("non-method call to method without first arg: %+N", n);
|
fatal("non-method call to method without first arg: %+N", n);
|
||||||
if(t != T && t->nname != N && !isblank(t->nname))
|
if(t != T)
|
||||||
as = nod(OAS, t->nname->inlvar, n->list->n);
|
as = nod(OAS, tinlvar(t), n->list->n);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(as != N) {
|
if(as != N) {
|
||||||
@ -601,27 +611,16 @@ mkinlcall1(Node **np, Node *fn)
|
|||||||
// TODO check that n->list->n is a call?
|
// TODO check that n->list->n is a call?
|
||||||
// TODO: non-method call to T.meth(f()) where f returns t, args...
|
// TODO: non-method call to T.meth(f()) where f returns t, args...
|
||||||
as->rlist = n->list;
|
as->rlist = n->list;
|
||||||
for(t = getinargx(fn->type)->type; t; t=t->down) {
|
for(t = getinargx(fn->type)->type; t; t=t->down)
|
||||||
if(t->nname && !isblank(t->nname)) {
|
as->list = list(as->list, tinlvar(t));
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ll = n->list;
|
ll = n->list;
|
||||||
if(fn->type->thistuple && n->left->op != ODOTMETH) // non method call to method
|
if(fn->type->thistuple && n->left->op != ODOTMETH) // non method call to method
|
||||||
ll=ll->next; // was handled above in if(thistuple)
|
ll=ll->next; // was handled above in if(thistuple)
|
||||||
|
|
||||||
for(t = getinargx(fn->type)->type; t && ll; t=t->down) {
|
for(t = getinargx(fn->type)->type; t && ll; t=t->down) {
|
||||||
if(t->nname && !isblank(t->nname)) {
|
as->list = list(as->list, tinlvar(t));
|
||||||
if(!t->nname->inlvar)
|
as->rlist = list(as->rlist, ll->n);
|
||||||
fatal("missing inlvar for %N\n", t->nname);
|
|
||||||
as->list = list(as->list, t->nname->inlvar);
|
|
||||||
as->rlist = list(as->rlist, ll->n);
|
|
||||||
}
|
|
||||||
ll=ll->next;
|
ll=ll->next;
|
||||||
}
|
}
|
||||||
if(ll || t)
|
if(ll || t)
|
||||||
|
36
test/fixedbugs/bug441.go
Normal file
36
test/fixedbugs/bug441.go
Normal 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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user