]> Cypherpunks.ru repositories - gostls13.git/commitdiff
gc: allow taking address of out parameters
authorRuss Cox <rsc@golang.org>
Sat, 27 Mar 2010 01:01:02 +0000 (18:01 -0700)
committerRuss Cox <rsc@golang.org>
Sat, 27 Mar 2010 01:01:02 +0000 (18:01 -0700)
Fixes #186.

R=ken2
CC=golang-dev
https://golang.org/cl/793041

doc/go_spec.html
src/cmd/5g/ggen.c
src/cmd/6g/ggen.c
src/cmd/8g/ggen.c
src/cmd/gc/typecheck.c
src/cmd/gc/walk.c
test/escape.go
test/escape1.go [deleted file]

index 46dc33e8a09f1ca9b1a24428f9d83c257b3d877b..b35af9b037cdcac243016a30af2b2ef1ddaabd72 100644 (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">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>
index e2313d85b660ac407107a34b7ad1c9481e1c2338..c60c05863ac90e9664523d129a2fba39edf23dd1 100644 (file)
@@ -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
index 99a4aea0454e896b1b99a429775fe8af3235a339..140020fdafbac2747f2e1cff9671111c397df6da 100644 (file)
@@ -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);
 }
 
 /*
index 23177c2408f1c6f8e6b228154b0200cfa1fcb908..468f67ae982928428fa220647fc067714469c549 100644 (file)
@@ -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);
 }
 
 /*
index d10bf8f74bb549138367313b2e01eeecad4ee9fa..c219ad8c53cd44c4efcf41432030d0ac20ccb6ff 100644 (file)
@@ -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;
index 9c904f14c68d7aba92766f57a7b11c8eb1b9edff..fa6157bb027a38b6f81e446d0d53fc137875e775 100644 (file)
@@ -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*
index 2c5881d49c8d619fc8c6d18a6159dcd5ece08cb2..19c08a5276e57cd8a41940e156f7c83368490205 100644 (file)
@@ -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");
        }
diff --git a/test/escape1.go b/test/escape1.go
deleted file mode 100644 (file)
index 646e4b3..0000000
+++ /dev/null
@@ -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"
-}
-