Commit 97d0e8fe authored by Russ Cox's avatar Russ Cox

gc: allow taking address of out parameters

Fixes #186.

R=ken2
CC=golang-dev
https://golang.org/cl/793041
parent 5a716206
......@@ -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">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">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">The implemented version of panic differs from its specification.</span></li>
</ul>
......@@ -7,6 +7,8 @@
#include "gg.h"
#include "opt.h"
static Prog *pret;
void
compile(Node *fn)
{
......@@ -65,6 +67,16 @@ compile(Node *fn)
afunclit(&ptxt->from);
genlist(curfn->enter);
pret = nil;
if(hasdefer || curfn->exit) {
Prog *p1;
p1 = gjmp(nil);
pret = gjmp(nil);
patch(p1, pc);
}
genlist(curfn->nbody);
checklabels();
if(nerrors != 0)
......@@ -73,6 +85,14 @@ compile(Node *fn)
if(curfn->type->outtuple != 0)
ginscall(throwreturn, 0);
if(pret)
patch(pret, pc);
ginit();
if(curfn->exit)
genlist(curfn->exit);
gclean();
if(nerrors != 0)
goto ret;
if(hasdefer)
ginscall(deferreturn, 0);
pc->as = ARET; // overwrite AEND
......
......@@ -7,6 +7,8 @@
#include "gg.h"
#include "opt.h"
static Prog *pret;
void
compile(Node *fn)
{
......@@ -66,6 +68,16 @@ compile(Node *fn)
ginit();
genlist(curfn->enter);
pret = nil;
if(hasdefer || curfn->exit) {
Prog *p1;
p1 = gjmp(nil);
pret = gjmp(nil);
patch(p1, pc);
}
genlist(curfn->nbody);
gclean();
checklabels();
......@@ -75,6 +87,14 @@ compile(Node *fn)
if(curfn->type->outtuple != 0)
ginscall(throwreturn, 0);
if(pret)
patch(pret, pc);
ginit();
if(curfn->exit)
genlist(curfn->exit);
gclean();
if(nerrors != 0)
goto ret;
if(hasdefer)
ginscall(deferreturn, 0);
pc->as = ARET; // overwrite AEND
......@@ -325,8 +345,9 @@ void
cgen_ret(Node *n)
{
genlist(n->list); // copy out args
if(hasdefer)
ginscall(deferreturn, 0);
if(hasdefer || curfn->exit)
gjmp(pret);
else
gins(ARET, N, N);
}
......
......@@ -7,6 +7,8 @@
#include "gg.h"
#include "opt.h"
static Prog *pret;
void
compile(Node *fn)
{
......@@ -66,6 +68,16 @@ compile(Node *fn)
ginit();
genlist(curfn->enter);
pret = nil;
if(hasdefer || curfn->exit) {
Prog *p1;
p1 = gjmp(nil);
pret = gjmp(nil);
patch(p1, pc);
}
genlist(curfn->nbody);
gclean();
checklabels();
......@@ -75,6 +87,14 @@ compile(Node *fn)
if(curfn->type->outtuple != 0)
ginscall(throwreturn, 0);
if(pret)
patch(pret, pc);
ginit();
if(curfn->exit)
genlist(curfn->exit);
gclean();
if(nerrors != 0)
goto ret;
if(hasdefer)
ginscall(deferreturn, 0);
pc->as = ARET; // overwrite AEND
......@@ -362,8 +382,9 @@ void
cgen_ret(Node *n)
{
genlist(n->list); // copy out args
if(hasdefer)
ginscall(deferreturn, 0);
if(pret)
gjmp(pret);
else
gins(ARET, N, N);
}
......
......@@ -1988,17 +1988,15 @@ addrescapes(Node *n)
if(n->noescape)
break;
switch(n->class) {
case PPARAMOUT:
yyerror("cannot take address of out parameter %s", n->sym->name);
break;
case PAUTO:
case PPARAM:
case PPARAMOUT:
// if func param, need separate temporary
// to hold heap pointer.
// the function type has already been checked
// (we're in the function body)
// 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
n->stackparam = nod(OPARAM, n, N);
n->stackparam->type = n->type;
......
......@@ -2288,11 +2288,33 @@ paramstoheap(Type **argin)
if(v->alloc == nil)
v->alloc = callnew(v->type);
nn = list(nn, nod(OAS, v->heapaddr, v->alloc));
if((v->class & ~PHEAP) != PPARAMOUT)
nn = list(nn, nod(OAS, v, v->stackparam));
}
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
* between the stack and the heap. adds code to
......@@ -2305,7 +2327,9 @@ heapmoves(void)
nn = paramstoheap(getthis(curfn->type));
nn = concat(nn, paramstoheap(getinarg(curfn->type)));
nn = concat(nn, paramstoheap(getoutarg(curfn->type)));
curfn->enter = concat(curfn->enter, nn);
curfn->exit = returnsfromheap(getoutarg(curfn->type));
}
static Node*
......
......@@ -141,6 +141,24 @@ func for_escapes2(x int, y int) (*int, *int) {
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() {
p, q := i_escapes(1), i_escapes(2);
chk(p, q, 1, "i_escapes");
......@@ -169,6 +187,20 @@ func main() {
p, q = for_escapes2(103, 104);
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 {
panic("BUG: no escape");
}
......
// 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"
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment