mirror of
https://github.com/golang/go
synced 2024-11-13 14:10:22 -07:00
gc: better diagnosis of initialization loops
Fixes bug 292. R=ken2 https://golang.org/cl/164093
This commit is contained in:
parent
e733766dda
commit
41861a8812
@ -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)
|
|||||||
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
|
|||||||
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 @@
|
|||||||
|
|
||||||
#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)
|
|||||||
|
|
||||||
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)
|
|||||||
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:
|
|||||||
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[] =
|
|||||||
[OEQ] = "==",
|
[OEQ] = "==",
|
||||||
[OFALL] = "fallthrough",
|
[OFALL] = "fallthrough",
|
||||||
[OFOR] = "for",
|
[OFOR] = "for",
|
||||||
[OFUNC] = "func",
|
|
||||||
[OGE] = ">=",
|
[OGE] = ">=",
|
||||||
[OGOTO] = "goto",
|
[OGOTO] = "goto",
|
||||||
[OGT] = ">",
|
[OGT] = ">",
|
||||||
|
21
test/fixedbugs/bug223.go
Normal file
21
test/fixedbugs/bug223.go
Normal file
@ -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}
|
Loading…
Reference in New Issue
Block a user