summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2010-03-26 18:01:02 -0700
committerRuss Cox <rsc@golang.org>2010-03-26 18:01:02 -0700
commit564d135cebd96ee57a1351b53cc8bcc0aaba12b6 (patch)
treee5a03e10cafa59f726579395f85e30de69e0d1e1 /src
parent72bf519063879c7aa02cffc4045383d2671caf7f (diff)
downloadgolang-564d135cebd96ee57a1351b53cc8bcc0aaba12b6.tar.gz
gc: allow taking address of out parameters
Fixes issue 186. R=ken2 CC=golang-dev http://codereview.appspot.com/793041
Diffstat (limited to 'src')
-rw-r--r--src/cmd/5g/ggen.c20
-rw-r--r--src/cmd/6g/ggen.c27
-rw-r--r--src/cmd/8g/ggen.c27
-rw-r--r--src/cmd/gc/typecheck.c6
-rw-r--r--src/cmd/gc/walk.c26
5 files changed, 95 insertions, 11 deletions
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
index e2313d85b..c60c05863 100644
--- a/src/cmd/5g/ggen.c
+++ b/src/cmd/5g/ggen.c
@@ -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
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
index 99a4aea04..140020fda 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -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,9 +345,10 @@ void
cgen_ret(Node *n)
{
genlist(n->list); // copy out args
- if(hasdefer)
- ginscall(deferreturn, 0);
- gins(ARET, N, N);
+ if(hasdefer || curfn->exit)
+ gjmp(pret);
+ else
+ gins(ARET, N, N);
}
/*
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
index 23177c240..468f67ae9 100644
--- a/src/cmd/8g/ggen.c
+++ b/src/cmd/8g/ggen.c
@@ -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,9 +382,10 @@ void
cgen_ret(Node *n)
{
genlist(n->list); // copy out args
- if(hasdefer)
- ginscall(deferreturn, 0);
- gins(ARET, N, N);
+ if(pret)
+ gjmp(pret);
+ else
+ gins(ARET, N, N);
}
/*
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index d10bf8f74..c219ad8c5 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -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;
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 9c904f14c..fa6157bb0 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -2288,7 +2288,29 @@ paramstoheap(Type **argin)
if(v->alloc == nil)
v->alloc = callnew(v->type);
nn = list(nn, nod(OAS, v->heapaddr, v->alloc));
- nn = list(nn, nod(OAS, v, v->stackparam));
+ 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;
}
@@ -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*