diff options
author | Lorenzo Stoakes <lstoakes@gmail.com> | 2011-04-28 00:13:49 -0400 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2011-04-28 00:13:49 -0400 |
commit | b6f0632e93d183bc39031c475eb79ef1986bd226 (patch) | |
tree | 1c235dc6e106b86d4f005d4b4e73983daf7f6210 | |
parent | 370276a3e58c4794e1d604961274859fc6fc2501 (diff) | |
download | go-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.c | 10 | ||||
-rw-r--r-- | src/cmd/gc/go.h | 3 | ||||
-rw-r--r-- | src/cmd/gc/lex.c | 1 | ||||
-rw-r--r-- | src/cmd/gc/typecheck.c | 29 | ||||
-rw-r--r-- | src/cmd/gc/walk.c | 72 | ||||
-rw-r--r-- | test/fixedbugs/bug336.go | 86 |
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) +} |