aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorenzo Stoakes <lstoakes@gmail.com>2011-04-28 00:13:49 -0400
committerRuss Cox <rsc@golang.org>2011-04-28 00:13:49 -0400
commitb6f0632e93d183bc39031c475eb79ef1986bd226 (patch)
tree1c235dc6e106b86d4f005d4b4e73983daf7f6210
parent370276a3e58c4794e1d604961274859fc6fc2501 (diff)
downloadgo-b6f0632e93d183bc39031c475eb79ef1986bd226.tar.gz
go-b6f0632e93d183bc39031c475eb79ef1986bd226.zip
gc: correctly handle fields of pointer type to recursive forward references
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
-rw-r--r--src/cmd/gc/dcl.c10
-rw-r--r--src/cmd/gc/go.h3
-rw-r--r--src/cmd/gc/lex.c1
-rw-r--r--src/cmd/gc/typecheck.c29
-rw-r--r--src/cmd/gc/walk.c72
-rw-r--r--test/fixedbugs/bug336.go86
6 files changed, 181 insertions, 20 deletions
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index 05ec080392..99af18d9f1 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -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);
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 58f8acecbe..f58b767891 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -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);
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 18803938dd..04dd0d5b95 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -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)
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index beabfcae0e..c48bf7a29b 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -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;
+ }
+ }
+}
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index bee3c25b0d..278eef4145 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -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
index 0000000000..8de36898f8
--- /dev/null
+++ b/test/fixedbugs/bug336.go
@@ -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)
+}