Commit 41861a88 authored by Russ Cox's avatar Russ Cox

gc: better diagnosis of initialization loops

Fixes bug 292.

R=ken2
https://golang.org/cl/164093
parent e733766d
...@@ -152,9 +152,10 @@ walkclosure(Node *func, NodeList **init) ...@@ -152,9 +152,10 @@ walkclosure(Node *func, NodeList **init)
// create the function // create the function
xfunc = nod(ODCLFUNC, N, N); 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 = newname(lookup(namebuf));
xfunc->nname->ntype = xtype; xfunc->nname->ntype = xtype;
xfunc->nname->defn = xfunc;
declare(xfunc->nname, PFUNC); declare(xfunc->nname, PFUNC);
xfunc->nname->funcdepth = func->funcdepth; xfunc->nname->funcdepth = func->funcdepth;
xfunc->funcdepth = func->funcdepth; xfunc->funcdepth = func->funcdepth;
......
...@@ -167,6 +167,7 @@ declare(Node *n, int ctxt) ...@@ -167,6 +167,7 @@ declare(Node *n, int ctxt)
if(isblank(n)) if(isblank(n))
return; return;
n->lineno = parserline();
s = n->sym; s = n->sym;
gen = 0; gen = 0;
if(ctxt == PEXTERN) { if(ctxt == PEXTERN) {
......
...@@ -351,7 +351,6 @@ enum ...@@ -351,7 +351,6 @@ enum
ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT,
ODOTTYPE, ODOTTYPE,
OEQ, ONE, OLT, OLE, OGE, OGT, OEQ, ONE, OLT, OLE, OGE, OGT,
OFUNC,
OIND, OIND,
OINDEX, OINDEXSTR, OINDEXMAP, OINDEX, OINDEXSTR, OINDEXMAP,
OKEY, OPARAM, OKEY, OPARAM,
......
...@@ -8,6 +8,10 @@ ...@@ -8,6 +8,10 @@
#include "go.h" #include "go.h"
static NodeList *initlist;
static void init2(Node*, NodeList**);
static void init2list(NodeList*, NodeList**);
static void static void
init1(Node *n, NodeList **out) init1(Node *n, NodeList **out)
{ {
...@@ -34,20 +38,45 @@ init1(Node *n, NodeList **out) ...@@ -34,20 +38,45 @@ init1(Node *n, NodeList **out)
if(n->initorder == 1) if(n->initorder == 1)
return; return;
if(n->initorder == 2) if(n->initorder == 2) {
fatal("init loop"); 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. // make sure that everything n depends on is initialized.
// n->defn is an assignment to n // n->defn is an assignment to n
n->initorder = 2;
if(n->defn != N) { if(n->defn != N) {
switch(n->defn->op) { switch(n->defn->op) {
default: default:
goto bad; goto bad;
case ODCLFUNC: case ODCLFUNC:
for(l=n->defn->nbody; l; l=l->next) init2list(n->defn->nbody, out);
init1(l->n, out);
break; break;
case OAS: case OAS:
...@@ -67,6 +96,11 @@ init1(Node *n, NodeList **out) ...@@ -67,6 +96,11 @@ init1(Node *n, NodeList **out)
break; break;
} }
} }
l = initlist;
initlist = l->next;
if(l->n != n)
fatal("bad initlist");
free(l);
n->initorder = 1; n->initorder = 1;
return; return;
...@@ -75,6 +109,31 @@ bad: ...@@ -75,6 +109,31 @@ bad:
fatal("init1: bad defn"); 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 static void
initreorder(NodeList *l, NodeList **out) initreorder(NodeList *l, NodeList **out)
{ {
......
...@@ -753,7 +753,6 @@ goopnames[] = ...@@ -753,7 +753,6 @@ goopnames[] =
[OEQ] = "==", [OEQ] = "==",
[OFALL] = "fallthrough", [OFALL] = "fallthrough",
[OFOR] = "for", [OFOR] = "for",
[OFUNC] = "func",
[OGE] = ">=", [OGE] = ">=",
[OGOTO] = "goto", [OGOTO] = "goto",
[OGT] = ">", [OGT] = ">",
......
// (! $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}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment