]> Cypherpunks repositories - gostls13.git/commitdiff
gc: better diagnosis of initialization loops
authorRuss Cox <rsc@golang.org>
Thu, 3 Dec 2009 08:51:03 +0000 (00:51 -0800)
committerRuss Cox <rsc@golang.org>
Thu, 3 Dec 2009 08:51:03 +0000 (00:51 -0800)
Fixes bug 292.

R=ken2
https://golang.org/cl/164093

src/cmd/gc/closure.c
src/cmd/gc/dcl.c
src/cmd/gc/go.h
src/cmd/gc/sinit.c
src/cmd/gc/subr.c
test/fixedbugs/bug223.go [new file with mode: 0644]

index 2f102993c6fa9b2aa7b604e7ca313ac07b32cd68..33c576c878e2165774c211132de2b9f66dedc4f5 100644 (file)
@@ -152,9 +152,10 @@ walkclosure(Node *func, NodeList **init)
 
        // create the function
        xfunc = nod(ODCLFUNC, N, N);
-       snprint(namebuf, sizeof namebuf, "_f%.3ld", ++closgen);
+       snprint(namebuf, sizeof namebuf, "_func_%.3ld", ++closgen);
        xfunc->nname = newname(lookup(namebuf));
        xfunc->nname->ntype = xtype;
+       xfunc->nname->defn = xfunc;
        declare(xfunc->nname, PFUNC);
        xfunc->nname->funcdepth = func->funcdepth;
        xfunc->funcdepth = func->funcdepth;
index ec386f3a0cb808b6d4912967dd35c16aeb30298b..338a6213a688a4d73aedd3c937b3ef4d2395c2aa 100644 (file)
@@ -167,6 +167,7 @@ declare(Node *n, int ctxt)
        if(isblank(n))
                return;
 
+       n->lineno = parserline();
        s = n->sym;
        gen = 0;
        if(ctxt == PEXTERN) {
index 595d7c8b8c71d01b03ef27ff040d42e0c431e96b..87362156d3d2b572174067022928bafb0dc360fd 100644 (file)
@@ -351,7 +351,6 @@ enum
        ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT,
        ODOTTYPE,
        OEQ, ONE, OLT, OLE, OGE, OGT,
-       OFUNC,
        OIND,
        OINDEX, OINDEXSTR, OINDEXMAP,
        OKEY, OPARAM,
index dc95360ee88a63a7215464d8348d38bb65d14669..ade8426c02ef1d73e511ec6b5f0f28fc250fda52 100644 (file)
@@ -8,6 +8,10 @@
 
 #include       "go.h"
 
+static NodeList *initlist;
+static void init2(Node*, NodeList**);
+static void init2list(NodeList*, NodeList**);
+
 static void
 init1(Node *n, NodeList **out)
 {
@@ -34,20 +38,45 @@ init1(Node *n, NodeList **out)
 
        if(n->initorder == 1)
                return;
-       if(n->initorder == 2)
-               fatal("init loop");
+       if(n->initorder == 2) {
+               if(n->class == PFUNC)
+                       return;
+               
+               // if there have already been errors printed,
+               // those errors probably confused us and
+               // there might not be a loop.  let the user
+               // fix those first.
+               flusherrors();
+               if(nerrors > 0)
+                       errorexit();
+
+               print("initialization loop:\n");
+               for(l=initlist;; l=l->next) {
+                       if(l->next == nil)
+                               break;
+                       l->next->end = l;
+               }
+               for(; l; l=l->end)
+                       print("\t%L %S refers to\n", l->n->lineno, l->n->sym);
+               print("\t%L %S\n", n->lineno, n->sym);
+               errorexit();
+       }
+       n->initorder = 2;
+       l = malloc(sizeof *l);
+       l->next = initlist;
+       l->n = n;
+       l->end = nil;
+       initlist = l;
 
        // make sure that everything n depends on is initialized.
        // n->defn is an assignment to n
-       n->initorder = 2;
        if(n->defn != N) {
                switch(n->defn->op) {
                default:
                        goto bad;
 
                case ODCLFUNC:
-                       for(l=n->defn->nbody; l; l=l->next)
-                               init1(l->n, out);
+                       init2list(n->defn->nbody, out);
                        break;
 
                case OAS:
@@ -67,6 +96,11 @@ init1(Node *n, NodeList **out)
                        break;
                }
        }
+       l = initlist;
+       initlist = l->next;
+       if(l->n != n)
+               fatal("bad initlist");
+       free(l);
        n->initorder = 1;
        return;
 
@@ -75,6 +109,31 @@ bad:
        fatal("init1: bad defn");
 }
 
+// recurse over n, doing init1 everywhere.
+static void
+init2(Node *n, NodeList **out)
+{
+       if(n == N || n->initorder == 1)
+               return;
+       init1(n, out);
+       init2(n->left, out);
+       init2(n->right, out);
+       init2(n->ntest, out);
+       init2list(n->ninit, out);
+       init2list(n->list, out);
+       init2list(n->rlist, out);
+       init2list(n->nbody, out);
+       init2list(n->nelse, out);
+}
+
+static void
+init2list(NodeList *l, NodeList **out)
+{
+       for(; l; l=l->next)
+               init2(l->n, out);
+}
+
+
 static void
 initreorder(NodeList *l, NodeList **out)
 {
index 22e59c5c807ecea30e56a90a3ed786cc710a0240..6b73570e527b19d81a371c3eaff2f76ab84bfb5e 100644 (file)
@@ -753,7 +753,6 @@ goopnames[] =
        [OEQ]           = "==",
        [OFALL]         = "fallthrough",
        [OFOR]          = "for",
-       [OFUNC]         = "func",
        [OGE]           = ">=",
        [OGOTO]         = "goto",
        [OGT]           = ">",
diff --git a/test/fixedbugs/bug223.go b/test/fixedbugs/bug223.go
new file mode 100644 (file)
index 0000000..80f9cae
--- /dev/null
@@ -0,0 +1,21 @@
+// (! $G $D/$F.go) | grep 'initialization loop' >/dev/null || echo BUG: bug223
+
+// 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.
+
+// check that initialization loop is diagnosed
+// and that closure cannot be used to hide it.
+// error message is not standard format, so no errchk above.
+
+package main
+
+type F func()
+
+func f() {
+       if true {
+               _ = func() { _ = m }
+       }
+}
+
+var m = map[string]F{"f": f}