mirror of
https://github.com/golang/go
synced 2024-11-24 23:17:57 -07:00
gc: fix closure bug
Fixes #2056. R=rsc CC=golang-dev https://golang.org/cl/4709042
This commit is contained in:
parent
cbad580e9c
commit
e8ff9a624f
@ -116,12 +116,11 @@ typecheckclosure(Node *func, int top)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Node*
|
static Node*
|
||||||
walkclosure(Node *func, NodeList **init)
|
makeclosure(Node *func, NodeList **init, int nowrap)
|
||||||
{
|
{
|
||||||
int narg;
|
Node *xtype, *v, *addr, *xfunc;
|
||||||
Node *xtype, *v, *addr, *xfunc, *call, *clos;
|
NodeList *l;
|
||||||
NodeList *l, *in;
|
|
||||||
static int closgen;
|
static int closgen;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
@ -133,7 +132,6 @@ walkclosure(Node *func, NodeList **init)
|
|||||||
|
|
||||||
// each closure variable has a corresponding
|
// each closure variable has a corresponding
|
||||||
// address parameter.
|
// address parameter.
|
||||||
narg = 0;
|
|
||||||
for(l=func->cvars; l; l=l->next) {
|
for(l=func->cvars; l; l=l->next) {
|
||||||
v = l->n;
|
v = l->n;
|
||||||
if(v->op == 0)
|
if(v->op == 0)
|
||||||
@ -146,7 +144,6 @@ walkclosure(Node *func, NodeList **init)
|
|||||||
addr->class = PPARAM;
|
addr->class = PPARAM;
|
||||||
addr->addable = 1;
|
addr->addable = 1;
|
||||||
addr->ullman = 1;
|
addr->ullman = 1;
|
||||||
narg++;
|
|
||||||
|
|
||||||
v->heapaddr = addr;
|
v->heapaddr = addr;
|
||||||
|
|
||||||
@ -154,7 +151,8 @@ walkclosure(Node *func, NodeList **init)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// then a dummy arg where the closure's caller pc sits
|
// then a dummy arg where the closure's caller pc sits
|
||||||
xtype->list = list(xtype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
|
if (!nowrap)
|
||||||
|
xtype->list = list(xtype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
|
||||||
|
|
||||||
// then the function arguments
|
// then the function arguments
|
||||||
xtype->list = concat(xtype->list, func->list);
|
xtype->list = concat(xtype->list, func->list);
|
||||||
@ -176,15 +174,36 @@ walkclosure(Node *func, NodeList **init)
|
|||||||
typecheck(&xfunc, Etop);
|
typecheck(&xfunc, Etop);
|
||||||
closures = list(closures, xfunc);
|
closures = list(closures, xfunc);
|
||||||
|
|
||||||
|
return xfunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node*
|
||||||
|
walkclosure(Node *func, NodeList **init)
|
||||||
|
{
|
||||||
|
int narg;
|
||||||
|
Node *xtype, *xfunc, *call, *clos;
|
||||||
|
NodeList *l, *in;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wrap body in external function
|
||||||
|
* with extra closure parameters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// create the function
|
||||||
|
xfunc = makeclosure(func, init, 0);
|
||||||
|
xtype = xfunc->nname->ntype;
|
||||||
|
|
||||||
// prepare call of sys.closure that turns external func into func literal value.
|
// prepare call of sys.closure that turns external func into func literal value.
|
||||||
clos = syslook("closure", 1);
|
clos = syslook("closure", 1);
|
||||||
clos->type = T;
|
clos->type = T;
|
||||||
clos->ntype = nod(OTFUNC, N, N);
|
clos->ntype = nod(OTFUNC, N, N);
|
||||||
in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // siz
|
in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // siz
|
||||||
in = list(in, nod(ODCLFIELD, N, xtype));
|
in = list(in, nod(ODCLFIELD, N, xtype));
|
||||||
|
narg = 0;
|
||||||
for(l=func->cvars; l; l=l->next) {
|
for(l=func->cvars; l; l=l->next) {
|
||||||
if(l->n->op == 0)
|
if(l->n->op == 0)
|
||||||
continue;
|
continue;
|
||||||
|
narg++;
|
||||||
in = list(in, nod(ODCLFIELD, N, l->n->heapaddr->ntype));
|
in = list(in, nod(ODCLFIELD, N, l->n->heapaddr->ntype));
|
||||||
}
|
}
|
||||||
clos->ntype->list = in;
|
clos->ntype->list = in;
|
||||||
@ -211,33 +230,18 @@ walkclosure(Node *func, NodeList **init)
|
|||||||
void
|
void
|
||||||
walkcallclosure(Node *n, NodeList **init)
|
walkcallclosure(Node *n, NodeList **init)
|
||||||
{
|
{
|
||||||
Node *z;
|
if (n->op != OCALLFUNC || n->left->op != OCLOSURE) {
|
||||||
NodeList *ll, *cargs;
|
dump("walkcallclosure", n);
|
||||||
|
fatal("abuse of walkcallclosure");
|
||||||
|
}
|
||||||
|
|
||||||
walkexpr(&n->left, init);
|
// New arg list for n. First the closure-args
|
||||||
cargs = n->left // FUNC runtime.closure
|
// and then the original parameter list.
|
||||||
->list // arguments
|
n->list = concat(n->left->enter, n->list);
|
||||||
->next // skip first
|
n->left = makeclosure(n->left, init, 1)->nname;
|
||||||
->next; // skip second
|
dowidth(n->left->type);
|
||||||
|
n->type = getoutargx(n->left->type);
|
||||||
n->left = n->left // FUNC runtime.closure
|
// for a single valued function, pull the field type out of the struct
|
||||||
->list // arguments
|
if (n->type && n->type->type && !n->type->type->down)
|
||||||
->next // skip first
|
n->type = n->type->type->type;
|
||||||
->n // AS (to indreg)
|
|
||||||
->right; // argument == the generated function
|
|
||||||
|
|
||||||
// New arg list for n. First the closure-args, stolen from
|
|
||||||
// runtime.closure's 3rd and following,
|
|
||||||
ll = nil;
|
|
||||||
for (; cargs; cargs = cargs->next)
|
|
||||||
ll = list(ll, cargs->n->right); // cargs->n is the OAS(INDREG, arg)
|
|
||||||
|
|
||||||
// then an extra zero, to fill the dummy return pointer slot,
|
|
||||||
z = nod(OXXX, N, N);
|
|
||||||
nodconst(z, types[TUINTPTR], 0);
|
|
||||||
z->typecheck = 1;
|
|
||||||
ll = list(ll, z);
|
|
||||||
|
|
||||||
// and finally the original parameter list.
|
|
||||||
n->list = concat(ll, n->list);
|
|
||||||
}
|
}
|
||||||
|
@ -494,9 +494,9 @@ walkexpr(Node **np, NodeList **init)
|
|||||||
if(n->left->op == OCLOSURE) {
|
if(n->left->op == OCLOSURE) {
|
||||||
walkcallclosure(n, init);
|
walkcallclosure(n, init);
|
||||||
t = n->left->type;
|
t = n->left->type;
|
||||||
} else
|
}
|
||||||
walkexpr(&n->left, init);
|
|
||||||
|
|
||||||
|
walkexpr(&n->left, init);
|
||||||
walkexprlist(n->list, init);
|
walkexprlist(n->list, init);
|
||||||
|
|
||||||
ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
|
ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
|
||||||
|
19
test/fixedbugs/bug346.go
Normal file
19
test/fixedbugs/bug346.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: issue2056
|
||||||
|
|
||||||
|
// Copyright 2011 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
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
x := 4
|
||||||
|
a, b, c, d := func(i int) (p int, q int, r int, s int) { return 1, i, 3, x }(2)
|
||||||
|
|
||||||
|
if a != 1 || b != 2 || c != 3 || d != 4 {
|
||||||
|
println("abcd: expected 1 2 3 4 got", a, b, c, d)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user