gc: better diagnosis of initialization loops
Fixes bug 292.
R=ken2
https://golang.org/cl/164093
diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c
index 2f10299..33c576c 100644
--- a/src/cmd/gc/closure.c
+++ b/src/cmd/gc/closure.c
@@ -152,9 +152,10 @@
// 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;
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index ec386f3..338a621 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -167,6 +167,7 @@
if(isblank(n))
return;
+ n->lineno = parserline();
s = n->sym;
gen = 0;
if(ctxt == PEXTERN) {
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 595d7c8..8736215 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -351,7 +351,6 @@
ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT,
ODOTTYPE,
OEQ, ONE, OLT, OLE, OGE, OGT,
- OFUNC,
OIND,
OINDEX, OINDEXSTR, OINDEXMAP,
OKEY, OPARAM,
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
index dc95360..ade8426 100644
--- a/src/cmd/gc/sinit.c
+++ b/src/cmd/gc/sinit.c
@@ -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 @@
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 @@
break;
}
}
+ l = initlist;
+ initlist = l->next;
+ if(l->n != n)
+ fatal("bad initlist");
+ free(l);
n->initorder = 1;
return;
@@ -75,6 +109,31 @@
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)
{
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 22e59c5..6b73570 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -753,7 +753,6 @@
[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
index 0000000..80f9cae
--- /dev/null
+++ b/test/fixedbugs/bug223.go
@@ -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}