1
0
mirror of https://github.com/golang/go synced 2024-11-25 04:47:57 -07:00

gc: allow taking address of out parameters

Fixes #186.

R=ken2
CC=golang-dev
https://golang.org/cl/793041
This commit is contained in:
Russ Cox 2010-03-26 18:01:02 -07:00
parent 5a716206a4
commit 97d0e8fe6c
8 changed files with 128 additions and 29 deletions

View File

@ -5109,7 +5109,7 @@ The following minimal alignment properties are guaranteed:
<li><span class="alert">Method expressions are partially implemented.</span></li> <li><span class="alert">Method expressions are partially implemented.</span></li>
<li><span class="alert">Gccgo allows only one init() function per source file.</span></li> <li><span class="alert">Gccgo allows only one init() function per source file.</span></li>
<li><span class="alert">Deferred functions cannot access the surrounding function's result parameters.</span></li> <li><span class="alert">Deferred functions cannot access the surrounding function's result parameters.</span></li>
<li><span class="alert">Function results are not addressable.</span></li> <li><span class="alert">Function results are not addressable in gccgo.</span></li>
<li><span class="alert">Recover is not implemented.</span></li> <li><span class="alert">Recover is not implemented.</span></li>
<li><span class="alert">The implemented version of panic differs from its specification.</span></li> <li><span class="alert">The implemented version of panic differs from its specification.</span></li>
</ul> </ul>

View File

@ -7,6 +7,8 @@
#include "gg.h" #include "gg.h"
#include "opt.h" #include "opt.h"
static Prog *pret;
void void
compile(Node *fn) compile(Node *fn)
{ {
@ -65,6 +67,16 @@ compile(Node *fn)
afunclit(&ptxt->from); afunclit(&ptxt->from);
genlist(curfn->enter); genlist(curfn->enter);
pret = nil;
if(hasdefer || curfn->exit) {
Prog *p1;
p1 = gjmp(nil);
pret = gjmp(nil);
patch(p1, pc);
}
genlist(curfn->nbody); genlist(curfn->nbody);
checklabels(); checklabels();
if(nerrors != 0) if(nerrors != 0)
@ -73,6 +85,14 @@ compile(Node *fn)
if(curfn->type->outtuple != 0) if(curfn->type->outtuple != 0)
ginscall(throwreturn, 0); ginscall(throwreturn, 0);
if(pret)
patch(pret, pc);
ginit();
if(curfn->exit)
genlist(curfn->exit);
gclean();
if(nerrors != 0)
goto ret;
if(hasdefer) if(hasdefer)
ginscall(deferreturn, 0); ginscall(deferreturn, 0);
pc->as = ARET; // overwrite AEND pc->as = ARET; // overwrite AEND

View File

@ -7,6 +7,8 @@
#include "gg.h" #include "gg.h"
#include "opt.h" #include "opt.h"
static Prog *pret;
void void
compile(Node *fn) compile(Node *fn)
{ {
@ -66,6 +68,16 @@ compile(Node *fn)
ginit(); ginit();
genlist(curfn->enter); genlist(curfn->enter);
pret = nil;
if(hasdefer || curfn->exit) {
Prog *p1;
p1 = gjmp(nil);
pret = gjmp(nil);
patch(p1, pc);
}
genlist(curfn->nbody); genlist(curfn->nbody);
gclean(); gclean();
checklabels(); checklabels();
@ -75,6 +87,14 @@ compile(Node *fn)
if(curfn->type->outtuple != 0) if(curfn->type->outtuple != 0)
ginscall(throwreturn, 0); ginscall(throwreturn, 0);
if(pret)
patch(pret, pc);
ginit();
if(curfn->exit)
genlist(curfn->exit);
gclean();
if(nerrors != 0)
goto ret;
if(hasdefer) if(hasdefer)
ginscall(deferreturn, 0); ginscall(deferreturn, 0);
pc->as = ARET; // overwrite AEND pc->as = ARET; // overwrite AEND
@ -325,8 +345,9 @@ void
cgen_ret(Node *n) cgen_ret(Node *n)
{ {
genlist(n->list); // copy out args genlist(n->list); // copy out args
if(hasdefer) if(hasdefer || curfn->exit)
ginscall(deferreturn, 0); gjmp(pret);
else
gins(ARET, N, N); gins(ARET, N, N);
} }

View File

@ -7,6 +7,8 @@
#include "gg.h" #include "gg.h"
#include "opt.h" #include "opt.h"
static Prog *pret;
void void
compile(Node *fn) compile(Node *fn)
{ {
@ -66,6 +68,16 @@ compile(Node *fn)
ginit(); ginit();
genlist(curfn->enter); genlist(curfn->enter);
pret = nil;
if(hasdefer || curfn->exit) {
Prog *p1;
p1 = gjmp(nil);
pret = gjmp(nil);
patch(p1, pc);
}
genlist(curfn->nbody); genlist(curfn->nbody);
gclean(); gclean();
checklabels(); checklabels();
@ -75,6 +87,14 @@ compile(Node *fn)
if(curfn->type->outtuple != 0) if(curfn->type->outtuple != 0)
ginscall(throwreturn, 0); ginscall(throwreturn, 0);
if(pret)
patch(pret, pc);
ginit();
if(curfn->exit)
genlist(curfn->exit);
gclean();
if(nerrors != 0)
goto ret;
if(hasdefer) if(hasdefer)
ginscall(deferreturn, 0); ginscall(deferreturn, 0);
pc->as = ARET; // overwrite AEND pc->as = ARET; // overwrite AEND
@ -362,8 +382,9 @@ void
cgen_ret(Node *n) cgen_ret(Node *n)
{ {
genlist(n->list); // copy out args genlist(n->list); // copy out args
if(hasdefer) if(pret)
ginscall(deferreturn, 0); gjmp(pret);
else
gins(ARET, N, N); gins(ARET, N, N);
} }

View File

@ -1988,17 +1988,15 @@ addrescapes(Node *n)
if(n->noescape) if(n->noescape)
break; break;
switch(n->class) { switch(n->class) {
case PPARAMOUT:
yyerror("cannot take address of out parameter %s", n->sym->name);
break;
case PAUTO: case PAUTO:
case PPARAM: case PPARAM:
case PPARAMOUT:
// if func param, need separate temporary // if func param, need separate temporary
// to hold heap pointer. // to hold heap pointer.
// the function type has already been checked // the function type has already been checked
// (we're in the function body) // (we're in the function body)
// so the param already has a valid xoffset. // so the param already has a valid xoffset.
if(n->class == PPARAM) { if(n->class == PPARAM || n->class == PPARAMOUT) {
// expression to refer to stack copy // expression to refer to stack copy
n->stackparam = nod(OPARAM, n, N); n->stackparam = nod(OPARAM, n, N);
n->stackparam->type = n->type; n->stackparam->type = n->type;

View File

@ -2288,11 +2288,33 @@ paramstoheap(Type **argin)
if(v->alloc == nil) if(v->alloc == nil)
v->alloc = callnew(v->type); v->alloc = callnew(v->type);
nn = list(nn, nod(OAS, v->heapaddr, v->alloc)); nn = list(nn, nod(OAS, v->heapaddr, v->alloc));
if((v->class & ~PHEAP) != PPARAMOUT)
nn = list(nn, nod(OAS, v, v->stackparam)); nn = list(nn, nod(OAS, v, v->stackparam));
} }
return nn; return nn;
} }
/*
* walk through argout parameters copying back to stack
*/
NodeList*
returnsfromheap(Type **argin)
{
Type *t;
Iter savet;
Node *v;
NodeList *nn;
nn = nil;
for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
v = t->nname;
if(v == N || v->class != (PHEAP|PPARAMOUT))
continue;
nn = list(nn, nod(OAS, v->stackparam, v));
}
return nn;
}
/* /*
* take care of migrating any function in/out args * take care of migrating any function in/out args
* between the stack and the heap. adds code to * between the stack and the heap. adds code to
@ -2305,7 +2327,9 @@ heapmoves(void)
nn = paramstoheap(getthis(curfn->type)); nn = paramstoheap(getthis(curfn->type));
nn = concat(nn, paramstoheap(getinarg(curfn->type))); nn = concat(nn, paramstoheap(getinarg(curfn->type)));
nn = concat(nn, paramstoheap(getoutarg(curfn->type)));
curfn->enter = concat(curfn->enter, nn); curfn->enter = concat(curfn->enter, nn);
curfn->exit = returnsfromheap(getoutarg(curfn->type));
} }
static Node* static Node*

View File

@ -141,6 +141,24 @@ func for_escapes2(x int, y int) (*int, *int) {
return p[0], p[1] return p[0], p[1]
} }
func out_escapes(i int) (x int, p *int) {
x = i
p = &x; // ERROR "address of out parameter"
return;
}
func out_escapes_2(i int) (x int, p *int) {
x = i
return x, &x; // ERROR "address of out parameter"
}
func defer1(i int) (x int) {
c := make(chan int)
go func() { x = i; c <- 1 }()
<-c
return
}
func main() { func main() {
p, q := i_escapes(1), i_escapes(2); p, q := i_escapes(1), i_escapes(2);
chk(p, q, 1, "i_escapes"); chk(p, q, 1, "i_escapes");
@ -169,6 +187,20 @@ func main() {
p, q = for_escapes2(103, 104); p, q = for_escapes2(103, 104);
chkalias(p, q, 103, "for_escapes2"); chkalias(p, q, 103, "for_escapes2");
_, p = out_escapes(15)
_, q = out_escapes(16);
chk(p, q, 15, "out_escapes");
_, p = out_escapes_2(17)
_, q = out_escapes_2(18);
chk(p, q, 17, "out_escapes_2");
x := defer1(20)
if x != 20 {
println("defer failed", x)
bad = true
}
if bad { if bad {
panic("BUG: no escape"); panic("BUG: no escape");
} }

View File

@ -1,17 +0,0 @@
// errchk $G $D/$F.go
// Copyright 2009 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
func out_escapes() (x int, p *int) {
p = &x; // ERROR "address of out parameter"
return;
}
func out_escapes_2() (x int, p *int) {
return 2, &x; // ERROR "address of out parameter"
}