]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1] cmd/gc: fix type checking loop
authorRuss Cox <rsc@golang.org>
Wed, 13 Jun 2012 20:24:51 +0000 (16:24 -0400)
committerRuss Cox <rsc@golang.org>
Wed, 13 Jun 2012 20:24:51 +0000 (16:24 -0400)
««« backport e69400ace361
cmd/gc: fix type checking loop

CL 4313064 fixed its test case but did not address a
general enough problem:

type T1 struct { F *T2 }
type T2 T1
type T3 T2

could still end up copying the definition of T1 for T2
before T1 was done being evaluated, or T3 before T2
was done.

In order to propagate the updates correctly,
record a copy of an incomplete type for re-execution
once the type is completed. Roll back CL 4313064.

Fixes #3709.

R=ken2
CC=golang-dev, lstoakes
https://golang.org/cl/6301059

»»»

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

index 88ee8123685d46b07bf78d7b3a21a0b90974a6f7..43bd687936340e1ed8a0e9957344f2d2fd8e1524 100644 (file)
@@ -182,6 +182,9 @@ struct      Type
 
        int32   maplineno;      // first use of TFORW as map key
        int32   embedlineno;    // first use of TFORW as embedded type
+       
+       // for TFORW, where to copy the eventual value to
+       NodeList        *copyto;
 };
 #define        T       ((Type*)0)
 
@@ -1247,9 +1250,7 @@ int       islvalue(Node *n);
 Node*  typecheck(Node **np, int top);
 void   typechecklist(NodeList *l, int top);
 Node*  typecheckdef(Node *n);
-void   resumetypecopy(void);
 void   copytype(Node *n, Type *t);
-void   defertypecopy(Node *n, Type *t);
 void   queuemethod(Node *n);
 
 /*
index e71fd3848e7fd200fb3ba768bdfffa0ce30f8b10..624dfb0b4161b912751fdbf8966ac5809b536fa7 100644 (file)
@@ -348,7 +348,6 @@ 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();
 
        // Phase 3: Type check function bodies.
index 02d6cc477726bae95afe90ad8236cdf5e7007ba5..cc4faf5a7a851f3e87e27ee042dc7fae99f29344 100644 (file)
@@ -31,7 +31,6 @@ static void   checkassign(Node*);
 static void    checkassignlist(NodeList*);
 static void    stringtoarraylit(Node**);
 static Node*   resolve(Node*);
-static Type*   getforwtype(Node*);
 
 static NodeList*       typecheckdefstack;
 
@@ -237,7 +236,7 @@ typecheck1(Node **np, int top)
        Node *n, *l, *r;
        NodeList *args;
        int ok, ntop;
-       Type *t, *tp, *ft, *missing, *have, *badtype;
+       Type *t, *tp, *missing, *have, *badtype;
        Val v;
        char *why;
        
@@ -249,10 +248,6 @@ typecheck1(Node **np, int top)
                        goto error;
                }
 
-               // a dance to handle forward-declared recursive pointer types.
-               if(n->op == OTYPE && (ft = getforwtype(n->ntype)) != T)
-                       defertypecopy(n, ft);
-
                typecheckdef(n);
                n->realtype = n->type;
                if(n->op == ONONAME)
@@ -2616,26 +2611,6 @@ stringtoarraylit(Node **np)
        *np = nn;
 }
 
-static Type*
-getforwtype(Node *n)
-{
-       Node *f1, *f2;
-
-       for(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;
-               }
-       }
-}
 
 static int ntypecheckdeftype;
 static NodeList *methodqueue;
@@ -2673,49 +2648,24 @@ domethod(Node *n)
        checkwidth(n->type);
 }
 
-typedef struct NodeTypeList NodeTypeList;
-struct NodeTypeList {
-       Node *n;
-       Type *t;
-       NodeTypeList *next;
-};
-
-static NodeTypeList    *dntq;
-static NodeTypeList    *dntend;
+static NodeList *mapqueue;
 
 void
-defertypecopy(Node *n, Type *t)
+copytype(Node *n, Type *t)
 {
-       NodeTypeList *ntl;
+       int maplineno, embedlineno, lno;
+       NodeList *l;
 
-       if(n == N || t == T)
+       if(t->etype == TFORW) {
+               // This type isn't computed yet; when it is, update n.
+               t->copyto = list(t->copyto, n);
                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);
-}
+       maplineno = n->type->maplineno;
+       embedlineno = n->type->embedlineno;
 
-void
-copytype(Node *n, Type *t)
-{
+       l = n->type->copyto;
        *n->type = *t;
 
        t = n->type;
@@ -2728,12 +2678,32 @@ copytype(Node *n, Type *t)
        t->nod = N;
        t->printed = 0;
        t->deferwidth = 0;
+       t->copyto = nil;
+       
+       // Update nodes waiting on this type.
+       for(; l; l=l->next)
+               copytype(l->n, t);
+
+       // Double-check use of type as embedded type.
+       lno = lineno;
+       if(embedlineno) {
+               lineno = embedlineno;
+               if(isptr[t->etype])
+                       yyerror("embedded type cannot be a pointer");
+       }
+       lineno = lno;
+       
+       // Queue check for map until all the types are done settling.
+       if(maplineno) {
+               t->maplineno = maplineno;
+               mapqueue = list(mapqueue, n);
+       }
 }
 
 static void
 typecheckdeftype(Node *n)
 {
-       int maplineno, embedlineno, lno;
+       int lno;
        Type *t;
        NodeList *l;
 
@@ -2752,26 +2722,12 @@ typecheckdeftype(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.
        copytype(n, t);
 
-       // double-check use of type as map key.
-       if(maplineno) {
-               lineno = maplineno;
-               maptype(n->type, types[TBOOL]);
-       }
-       if(embedlineno) {
-               lineno = embedlineno;
-               if(isptr[t->etype])
-                       yyerror("embedded type cannot be a pointer");
-       }
-
 ret:
        lineno = lno;
 
@@ -2784,6 +2740,11 @@ ret:
                        for(; l; l=l->next)
                                domethod(l->n);
                }
+               for(l=mapqueue; l; l=l->next) {
+                       lineno = l->n->type->maplineno;
+                       maptype(l->n->type, types[TBOOL]);
+               }
+               lineno = lno;
        }
        ntypecheckdeftype--;
 }
diff --git a/test/fixedbugs/bug443.go b/test/fixedbugs/bug443.go
new file mode 100644 (file)
index 0000000..b67bd8c
--- /dev/null
@@ -0,0 +1,17 @@
+// compile
+
+// Copyright 2012 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.
+
+// Was failing to compile with 'invalid receiver' due to
+// incomplete type definition evaluation.  Issue 3709.
+
+package p
+
+type T1 struct { F *T2 }
+type T2 T1
+
+type T3 T2
+func (*T3) M()  // was invalid receiver
+
index 369e49da5d0bf4d1683f26f344f8a81435681928..6f1a1c8ac01c97288756dc5654acd189194f8807 100644 (file)
@@ -41,4 +41,22 @@ var (
        _ map[[]int]v       // ERROR "invalid map key"
        _ map[func()]v      // ERROR "invalid map key"
        _ map[map[int]int]v // ERROR "invalid map key"
+       _ map[T1]v    // ERROR "invalid map key"
+       _ map[T2]v    // ERROR "invalid map key"
+       _ map[T3]v    // ERROR "invalid map key"
+       _ map[T4]v    // ERROR "invalid map key"
+       _ map[T5]v
+       _ map[T6]v
+       _ map[T7]v
+       _ map[T8]v
 )
+
+type T1 []int
+type T2 struct { F T1 }
+type T3 []T4
+type T4 struct { F T3 }
+
+type T5 *int
+type T6 struct { F T5 }
+type T7 *T4
+type T8 struct { F *T7 }