]> Cypherpunks repositories - gostls13.git/commitdiff
gc: correctly handle fields of pointer type to recursive forward references
authorLorenzo Stoakes <lstoakes@gmail.com>
Thu, 28 Apr 2011 04:13:49 +0000 (00:13 -0400)
committerRuss Cox <rsc@golang.org>
Thu, 28 Apr 2011 04:13:49 +0000 (00:13 -0400)
Previously, whether declaring a type which copied the structure of a type it was referenced in via a pointer field would work depended on whether you declared it before or after the type it copied, e.g. type T2 T1; type T1 struct { F *T2 } would work, however type T1 struct { F *T2 }; type T2 T1 wouldn't.

Fixes #667.

R=rsc
CC=golang-dev
https://golang.org/cl/4313064

src/cmd/gc/dcl.c
src/cmd/gc/go.h
src/cmd/gc/lex.c
src/cmd/gc/typecheck.c
src/cmd/gc/walk.c
test/fixedbugs/bug336.go [new file with mode: 0644]

index 05ec0803925d0f3f0ce56bb35f550d170d6b4c85..99af18d9f11d5c2b336a523a74989b43efa06aa7 100644 (file)
@@ -679,15 +679,11 @@ typedcl2(Type *pt, Type *t)
 
 ok:
        n = pt->nod;
-       *pt = *t;
-       pt->method = nil;
+       copytype(pt->nod, t);
+       // unzero nod
        pt->nod = n;
-       pt->sym = n->sym;
+
        pt->sym->lastlineno = parserline();
-       pt->siggen = 0;
-       pt->printed = 0;
-       pt->deferwidth = 0;
-       pt->local = 0;
        declare(n, PEXTERN);
 
        checkwidth(pt);
index 58f8acecbe15c6e33b45f6831cc19f2899d8faf5..f58b7678916468fac848b4d0c6b97d895884d091 100644 (file)
@@ -1172,9 +1172,12 @@ Node*    unsafenmagic(Node *n);
  */
 Node*  callnew(Type *t);
 Node*  chanfn(char *name, int n, Type *t);
+void   copytype(Node *n, Type *t);
+void   defertypecopy(Node *n, Type *t);
 Node*  mkcall(char *name, Type *t, NodeList **init, ...);
 Node*  mkcall1(Node *fn, Type *t, NodeList **init, ...);
 void   queuemethod(Node *n);
+void   resumetypecopy(void);
 int    vmatch1(Node *l, Node *r);
 void   walk(Node *fn);
 Node*  walkdef(Node *n);
index 18803938ddc609cd5325980adb2fc388b3de16b1..04dd0d5b9507100fedcba7e286a8e13bda32bf57 100644 (file)
@@ -249,6 +249,7 @@ main(int argc, char *argv[])
        for(l=xtop; l; l=l->next)
                if(l->n->op == ODCL || l->n->op == OAS)
                        typecheck(&l->n, Etop);
+       resumetypecopy();
        resumecheckwidth();
        for(l=xtop; l; l=l->next)
                if(l->n->op == ODCLFUNC)
index beabfcae0e970dea309c5d93d511cb9185e0ee09..c48bf7a29b08c51211d1b150a56ad76dc8db731e 100644 (file)
@@ -31,6 +31,7 @@ static void   checkassign(Node*);
 static void    checkassignlist(NodeList*);
 static void stringtoarraylit(Node**);
 static Node* resolve(Node*);
+static Type*   getforwtype(Node*);
 
 /*
  * resolve ONONAME to definition, if any.
@@ -110,7 +111,7 @@ typecheck(Node **np, int top)
        Node *n, *l, *r;
        NodeList *args;
        int lno, ok, ntop;
-       Type *t, *tp, *missing, *have;
+       Type *t, *tp, *ft, *missing, *have;
        Sym *sym;
        Val v;
        char *why;
@@ -153,6 +154,11 @@ typecheck(Node **np, int top)
                        yyerror("use of builtin %S not in function call", n->sym);
                        goto error;
                }
+
+               // a dance to handle forward-declared recursive pointer types.
+               if(n->op == OTYPE && (ft = getforwtype(n->ntype)) != T)
+                       defertypecopy(n, ft);
+
                walkdef(n);
                n->realtype = n->type;
                if(n->op == ONONAME)
@@ -2470,3 +2476,24 @@ stringtoarraylit(Node **np)
        typecheck(&nn, Erv);
        *np = nn;
 }
+
+static Type*
+getforwtype(Node *n)
+{
+       Node *f1, *f2;
+
+       for(f1=f2=n; ; n=n->ntype) {
+               if((n = resolve(n)) == N || n->op != OTYPE)
+                       return T;
+
+               if(n->type != T && n->type->etype == TFORW)
+                       return n->type;
+
+               // Check for ntype cycle.
+               if((f2 = resolve(f2)) != N && (f1 = resolve(f2->ntype)) != N) {
+                       f2 = resolve(f1->ntype);
+                       if(f1 == n || f2 == n)
+                               return T;
+               }
+       }
+}
index bee3c25b0ddd7aa65d43c4fd80d128a1a8b3473d..278eef41454f07a87ea7aeb4ba2b7d2a85bfb492 100644 (file)
@@ -119,6 +119,62 @@ domethod(Node *n)
        checkwidth(n->type);
 }
 
+typedef struct NodeTypeList NodeTypeList;
+struct NodeTypeList {
+       Node *n;
+       Type *t;
+       NodeTypeList *next;
+};
+
+static NodeTypeList    *dntq;
+static NodeTypeList    *dntend;
+
+void
+defertypecopy(Node *n, Type *t)
+{
+       NodeTypeList *ntl;
+
+       if(n == N || t == T)
+               return;
+
+       ntl = mal(sizeof *ntl);
+       ntl->n = n;
+       ntl->t = t;
+       ntl->next = nil;
+
+       if(dntq == nil)
+               dntq = ntl;
+       else
+               dntend->next = ntl;
+
+       dntend = ntl;
+}
+
+void
+resumetypecopy(void)
+{
+       NodeTypeList *l;
+
+       for(l=dntq; l; l=l->next)
+               copytype(l->n, l->t);
+}
+
+void
+copytype(Node *n, Type *t)
+{
+       *n->type = *t;
+
+       t = n->type;
+       t->sym = n->sym;
+       t->local = n->local;
+       t->vargen = n->vargen;
+       t->siggen = 0;
+       t->method = nil;
+       t->nod = N;
+       t->printed = 0;
+       t->deferwidth = 0;
+}
+
 static void
 walkdeftype(Node *n)
 {
@@ -141,22 +197,14 @@ walkdeftype(Node *n)
                goto ret;
        }
 
+       maplineno = n->type->maplineno;
+       embedlineno = n->type->embedlineno;
+
        // copy new type and clear fields
        // that don't come along.
        // anything zeroed here must be zeroed in
        // typedcl2 too.
-       maplineno = n->type->maplineno;
-       embedlineno = n->type->embedlineno;
-       *n->type = *t;
-       t = n->type;
-       t->sym = n->sym;
-       t->local = n->local;
-       t->vargen = n->vargen;
-       t->siggen = 0;
-       t->method = nil;
-       t->nod = N;
-       t->printed = 0;
-       t->deferwidth = 0;
+       copytype(n, t);
 
        // double-check use of type as map key.
        if(maplineno) {
diff --git a/test/fixedbugs/bug336.go b/test/fixedbugs/bug336.go
new file mode 100644 (file)
index 0000000..8de3689
--- /dev/null
@@ -0,0 +1,86 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// 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
+
+type T1 struct {
+       Next *T2
+}
+
+type T2 T1
+
+type T3 struct {
+       Next *T4
+}
+
+type T4 T5
+type T5 T6
+type T6 T7
+type T7 T8
+type T8 T9
+type T9 T3
+
+type T10 struct {
+       x struct {
+               y ***struct {
+                       z *struct {
+                               Next *T11
+                       }
+               }
+       }
+}
+
+type T11 T10
+
+type T12 struct {
+       F1 *T15
+       F2 *T13
+       F3 *T16
+}
+
+type T13 T14
+type T14 T15
+type T15 T16
+type T16 T17
+type T17 T12
+
+// issue 1672
+type T18 *[10]T19
+type T19 T18
+
+func main() {
+       _ = &T1{&T2{}}
+       _ = &T2{&T2{}}
+       _ = &T3{&T4{}}
+       _ = &T4{&T4{}}
+       _ = &T5{&T4{}}
+       _ = &T6{&T4{}}
+       _ = &T7{&T4{}}
+       _ = &T8{&T4{}}
+       _ = &T9{&T4{}}
+       _ = &T12{&T15{}, &T13{}, &T16{}}
+
+       var (
+               tn    struct{ Next *T11 }
+               tz    struct{ z *struct{ Next *T11 } }
+               tpz   *struct{ z *struct{ Next *T11 } }
+               tppz  **struct{ z *struct{ Next *T11 } }
+               tpppz ***struct{ z *struct{ Next *T11 } }
+               ty    struct {
+                       y ***struct{ z *struct{ Next *T11 } }
+               }
+       )
+       tn.Next = &T11{}
+       tz.z = &tn
+       tpz = &tz
+       tppz = &tpz
+       tpppz = &tppz
+       ty.y = tpppz
+       _ = &T10{ty}
+
+       t19s := &[10]T19{}
+       _ = T18(t19s)
+}