mirror of
https://github.com/golang/go
synced 2024-11-25 15:57:57 -07:00
gc: implement goto restriction
Remove now-unnecessary zeroing of stack frames. R=ken2 CC=golang-dev https://golang.org/cl/4641044
This commit is contained in:
parent
e852202f37
commit
7f4c5ea7d8
@ -182,6 +182,8 @@ dumpfuncs(void)
|
|||||||
// fix up pc
|
// fix up pc
|
||||||
pcloc = 0;
|
pcloc = 0;
|
||||||
for(pl=plist; pl!=nil; pl=pl->link) {
|
for(pl=plist; pl!=nil; pl=pl->link) {
|
||||||
|
if(isblank(pl->name))
|
||||||
|
continue;
|
||||||
for(p=pl->firstpc; p!=P; p=p->link) {
|
for(p=pl->firstpc; p!=P; p=p->link) {
|
||||||
p->loc = pcloc;
|
p->loc = pcloc;
|
||||||
if(p->as != ADATA && p->as != AGLOBL)
|
if(p->as != ADATA && p->as != AGLOBL)
|
||||||
@ -191,6 +193,8 @@ dumpfuncs(void)
|
|||||||
|
|
||||||
// put out functions
|
// put out functions
|
||||||
for(pl=plist; pl!=nil; pl=pl->link) {
|
for(pl=plist; pl!=nil; pl=pl->link) {
|
||||||
|
if(isblank(pl->name))
|
||||||
|
continue;
|
||||||
|
|
||||||
if(debug['S']) {
|
if(debug['S']) {
|
||||||
s = S;
|
s = S;
|
||||||
|
@ -102,6 +102,21 @@ patch(Prog *p, Prog *to)
|
|||||||
p->to.offset = to->loc;
|
p->to.offset = to->loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Prog*
|
||||||
|
unpatch(Prog *p)
|
||||||
|
{
|
||||||
|
Prog *q;
|
||||||
|
|
||||||
|
if(p->to.type != D_BRANCH)
|
||||||
|
fatal("unpatch: not a branch");
|
||||||
|
if(p->to.branch == P)
|
||||||
|
fatal("unpatch: not patched");
|
||||||
|
q = p->to.branch;
|
||||||
|
p->to.branch = P;
|
||||||
|
p->to.offset = 0;
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* start a new Prog list.
|
* start a new Prog list.
|
||||||
*/
|
*/
|
||||||
|
@ -228,6 +228,8 @@ dumpfuncs(void)
|
|||||||
// fix up pc
|
// fix up pc
|
||||||
pcloc = 0;
|
pcloc = 0;
|
||||||
for(pl=plist; pl!=nil; pl=pl->link) {
|
for(pl=plist; pl!=nil; pl=pl->link) {
|
||||||
|
if(isblank(pl->name))
|
||||||
|
continue;
|
||||||
for(p=pl->firstpc; p!=P; p=p->link) {
|
for(p=pl->firstpc; p!=P; p=p->link) {
|
||||||
p->loc = pcloc;
|
p->loc = pcloc;
|
||||||
if(p->as != ADATA && p->as != AGLOBL)
|
if(p->as != ADATA && p->as != AGLOBL)
|
||||||
@ -237,6 +239,8 @@ dumpfuncs(void)
|
|||||||
|
|
||||||
// put out functions
|
// put out functions
|
||||||
for(pl=plist; pl!=nil; pl=pl->link) {
|
for(pl=plist; pl!=nil; pl=pl->link) {
|
||||||
|
if(isblank(pl->name))
|
||||||
|
continue;
|
||||||
|
|
||||||
if(debug['S']) {
|
if(debug['S']) {
|
||||||
s = S;
|
s = S;
|
||||||
|
@ -98,6 +98,19 @@ patch(Prog *p, Prog *to)
|
|||||||
p->to.offset = to->loc;
|
p->to.offset = to->loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Prog*
|
||||||
|
unpatch(Prog *p)
|
||||||
|
{
|
||||||
|
Prog *q;
|
||||||
|
|
||||||
|
if(p->to.type != D_BRANCH)
|
||||||
|
fatal("unpatch: not a branch");
|
||||||
|
q = p->to.branch;
|
||||||
|
p->to.branch = P;
|
||||||
|
p->to.offset = 0;
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* start a new Prog list.
|
* start a new Prog list.
|
||||||
*/
|
*/
|
||||||
|
@ -226,6 +226,8 @@ dumpfuncs(void)
|
|||||||
// fix up pc
|
// fix up pc
|
||||||
pcloc = 0;
|
pcloc = 0;
|
||||||
for(pl=plist; pl!=nil; pl=pl->link) {
|
for(pl=plist; pl!=nil; pl=pl->link) {
|
||||||
|
if(isblank(pl->name))
|
||||||
|
continue;
|
||||||
for(p=pl->firstpc; p!=P; p=p->link) {
|
for(p=pl->firstpc; p!=P; p=p->link) {
|
||||||
p->loc = pcloc;
|
p->loc = pcloc;
|
||||||
if(p->as != ADATA && p->as != AGLOBL)
|
if(p->as != ADATA && p->as != AGLOBL)
|
||||||
@ -235,6 +237,8 @@ dumpfuncs(void)
|
|||||||
|
|
||||||
// put out functions
|
// put out functions
|
||||||
for(pl=plist; pl!=nil; pl=pl->link) {
|
for(pl=plist; pl!=nil; pl=pl->link) {
|
||||||
|
if(isblank(pl->name))
|
||||||
|
continue;
|
||||||
|
|
||||||
if(debug['S']) {
|
if(debug['S']) {
|
||||||
s = S;
|
s = S;
|
||||||
|
@ -100,6 +100,21 @@ patch(Prog *p, Prog *to)
|
|||||||
p->to.offset = to->loc;
|
p->to.offset = to->loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Prog*
|
||||||
|
unpatch(Prog *p)
|
||||||
|
{
|
||||||
|
Prog *q;
|
||||||
|
|
||||||
|
if(p->to.type != D_BRANCH)
|
||||||
|
fatal("unpatch: not a branch");
|
||||||
|
if(p->to.branch == P)
|
||||||
|
fatal("unpatch: not patched");
|
||||||
|
q = p->to.branch;
|
||||||
|
p->to.branch = P;
|
||||||
|
p->to.offset = 0;
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* start a new Prog list.
|
* start a new Prog list.
|
||||||
*/
|
*/
|
||||||
|
@ -39,6 +39,7 @@ push(void)
|
|||||||
Sym *d;
|
Sym *d;
|
||||||
|
|
||||||
d = mal(sizeof(*d));
|
d = mal(sizeof(*d));
|
||||||
|
d->lastlineno = lineno;
|
||||||
d->link = dclstack;
|
d->link = dclstack;
|
||||||
dclstack = d;
|
dclstack = d;
|
||||||
return d;
|
return d;
|
||||||
@ -60,6 +61,7 @@ void
|
|||||||
popdcl(void)
|
popdcl(void)
|
||||||
{
|
{
|
||||||
Sym *d, *s;
|
Sym *d, *s;
|
||||||
|
int lno;
|
||||||
|
|
||||||
// if(dflag())
|
// if(dflag())
|
||||||
// print("revert\n");
|
// print("revert\n");
|
||||||
@ -68,7 +70,9 @@ popdcl(void)
|
|||||||
if(d->name == nil)
|
if(d->name == nil)
|
||||||
break;
|
break;
|
||||||
s = pkglookup(d->name, d->pkg);
|
s = pkglookup(d->name, d->pkg);
|
||||||
|
lno = s->lastlineno;
|
||||||
dcopy(s, d);
|
dcopy(s, d);
|
||||||
|
d->lastlineno = lno;
|
||||||
if(dflag())
|
if(dflag())
|
||||||
print("\t%L pop %S %p\n", lineno, s, s->def);
|
print("\t%L pop %S %p\n", lineno, s, s->def);
|
||||||
}
|
}
|
||||||
@ -81,19 +85,12 @@ popdcl(void)
|
|||||||
void
|
void
|
||||||
poptodcl(void)
|
poptodcl(void)
|
||||||
{
|
{
|
||||||
Sym *d, *s;
|
// pop the old marker and push a new one
|
||||||
|
// (cannot reuse the existing one)
|
||||||
for(d=dclstack; d!=S; d=d->link) {
|
// because we use the markers to identify blocks
|
||||||
if(d->name == nil)
|
// for the goto restriction checks.
|
||||||
break;
|
popdcl();
|
||||||
s = pkglookup(d->name, d->pkg);
|
markdcl();
|
||||||
dcopy(s, d);
|
|
||||||
if(dflag())
|
|
||||||
print("\t%L pop %S\n", lineno, s);
|
|
||||||
}
|
|
||||||
if(d == S)
|
|
||||||
fatal("poptodcl: no mark");
|
|
||||||
dclstack = d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1241,10 +1238,7 @@ funccompile(Node *n, int isclosure)
|
|||||||
stksize = 0;
|
stksize = 0;
|
||||||
dclcontext = PAUTO;
|
dclcontext = PAUTO;
|
||||||
funcdepth = n->funcdepth + 1;
|
funcdepth = n->funcdepth + 1;
|
||||||
hasgoto = 0;
|
|
||||||
compile(n);
|
compile(n);
|
||||||
if(hasgoto)
|
|
||||||
clearstk();
|
|
||||||
curfn = nil;
|
curfn = nil;
|
||||||
funcdepth = 0;
|
funcdepth = 0;
|
||||||
dclcontext = PEXTERN;
|
dclcontext = PEXTERN;
|
||||||
|
190
src/cmd/gc/gen.c
190
src/cmd/gc/gen.c
@ -11,6 +11,10 @@
|
|||||||
|
|
||||||
static void cgen_dcl(Node *n);
|
static void cgen_dcl(Node *n);
|
||||||
static void cgen_proc(Node *n, int proc);
|
static void cgen_proc(Node *n, int proc);
|
||||||
|
static void checkgoto(Node*, Node*);
|
||||||
|
|
||||||
|
static Label *labellist;
|
||||||
|
static Label *lastlabel;
|
||||||
|
|
||||||
Node*
|
Node*
|
||||||
sysfunc(char *name)
|
sysfunc(char *name)
|
||||||
@ -80,72 +84,123 @@ clearlabels(void)
|
|||||||
lastlabel = L;
|
lastlabel = L;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static Label*
|
||||||
newlab(int op, Node *nlab, Node *stmt)
|
newlab(Node *n)
|
||||||
{
|
{
|
||||||
Label *lab;
|
|
||||||
Sym *s;
|
Sym *s;
|
||||||
int32 lno;
|
Label *lab;
|
||||||
|
|
||||||
s = nlab->left->sym;
|
|
||||||
lno = nlab->left->lineno;
|
|
||||||
|
|
||||||
|
s = n->left->sym;
|
||||||
|
if((lab = s->label) == L) {
|
||||||
lab = mal(sizeof(*lab));
|
lab = mal(sizeof(*lab));
|
||||||
if(lastlabel == nil)
|
if(lastlabel == nil)
|
||||||
labellist = lab;
|
labellist = lab;
|
||||||
else
|
else
|
||||||
lastlabel->link = lab;
|
lastlabel->link = lab;
|
||||||
lastlabel = lab;
|
lastlabel = lab;
|
||||||
|
|
||||||
lab->lineno = lno;
|
|
||||||
lab->sym = s;
|
lab->sym = s;
|
||||||
lab->op = op;
|
|
||||||
lab->label = pc;
|
|
||||||
lab->stmt = stmt;
|
|
||||||
if(op == OLABEL) {
|
|
||||||
if(s->label != L) {
|
|
||||||
lineno = lno;
|
|
||||||
yyerror("label %S already defined at %L", s, s->label->lineno);
|
|
||||||
} else
|
|
||||||
s->label = lab;
|
s->label = lab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(n->op == OLABEL) {
|
||||||
|
if(lab->def != N)
|
||||||
|
yyerror("label %S already defined at %L", s, lab->def->lineno);
|
||||||
|
else
|
||||||
|
lab->def = n;
|
||||||
|
} else
|
||||||
|
lab->use = list(lab->use, n);
|
||||||
|
|
||||||
|
return lab;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
checklabels(void)
|
checklabels(void)
|
||||||
{
|
{
|
||||||
Label *l;
|
Label *lab;
|
||||||
Sym *s;
|
NodeList *l;
|
||||||
|
|
||||||
|
for(lab=labellist; lab!=L; lab=lab->link) {
|
||||||
|
if(lab->def == N) {
|
||||||
|
for(l=lab->use; l; l=l->next)
|
||||||
|
yyerrorl(l->n->lineno, "label %S not defined", lab->sym);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(lab->use == nil && !lab->used) {
|
||||||
|
yyerrorl(lab->def->lineno, "label %S defined and not used", lab->sym);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(lab->gotopc != P)
|
||||||
|
fatal("label %S never resolved", lab->sym);
|
||||||
|
for(l=lab->use; l; l=l->next)
|
||||||
|
checkgoto(l->n, lab->def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
checkgoto(Node *from, Node *to)
|
||||||
|
{
|
||||||
|
int nf, nt;
|
||||||
|
Sym *block, *dcl, *fs, *ts;
|
||||||
int lno;
|
int lno;
|
||||||
|
|
||||||
|
if(from->sym == to->sym)
|
||||||
|
return;
|
||||||
|
|
||||||
|
nf = 0;
|
||||||
|
for(fs=from->sym; fs; fs=fs->link)
|
||||||
|
nf++;
|
||||||
|
nt = 0;
|
||||||
|
for(fs=to->sym; fs; fs=fs->link)
|
||||||
|
nt++;
|
||||||
|
fs = from->sym;
|
||||||
|
for(; nf > nt; nf--)
|
||||||
|
fs = fs->link;
|
||||||
|
if(fs != to->sym) {
|
||||||
lno = lineno;
|
lno = lineno;
|
||||||
|
setlineno(from);
|
||||||
|
|
||||||
// resolve goto using syms
|
// decide what to complain about.
|
||||||
for(l=labellist; l!=L; l=l->link) {
|
// prefer to complain about 'into block' over declarations,
|
||||||
switch(l->op) {
|
// so scan backward to find most recent block or else dcl.
|
||||||
case OGOTO:
|
block = S;
|
||||||
s = l->sym;
|
dcl = S;
|
||||||
if(s->label == L) {
|
ts = to->sym;
|
||||||
lineno = l->lineno;
|
for(; nt > nf; nt--) {
|
||||||
yyerror("label %S not defined", s);
|
if(ts->pkg == nil)
|
||||||
break;
|
block = ts;
|
||||||
}
|
else
|
||||||
s->label->used = 1;
|
dcl = ts;
|
||||||
patch(l->label, s->label->label);
|
ts = ts->link;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// diagnose unused labels
|
|
||||||
for(l=labellist; l!=L; l=l->link) {
|
|
||||||
if(l->op == OLABEL && !l->used) {
|
|
||||||
lineno = l->lineno;
|
|
||||||
yyerror("label %S defined and not used", l->sym);
|
|
||||||
}
|
}
|
||||||
|
while(ts != fs) {
|
||||||
|
if(ts->pkg == nil)
|
||||||
|
block = ts;
|
||||||
|
else
|
||||||
|
dcl = ts;
|
||||||
|
ts = ts->link;
|
||||||
|
fs = fs->link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(block)
|
||||||
|
yyerror("goto %S jumps into block starting at %L", from->left->sym, block->lastlineno);
|
||||||
|
else
|
||||||
|
yyerror("goto %S jumps over declaration of %S at %L", from->left->sym, dcl, dcl->lastlineno);
|
||||||
lineno = lno;
|
lineno = lno;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Label*
|
||||||
|
stmtlabel(Node *n)
|
||||||
|
{
|
||||||
|
Label *lab;
|
||||||
|
|
||||||
|
if(n->sym != S)
|
||||||
|
if((lab = n->sym->label) != L)
|
||||||
|
if(lab->def != N)
|
||||||
|
if(lab->def->right == n)
|
||||||
|
return lab;
|
||||||
|
return L;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* compile statements
|
* compile statements
|
||||||
@ -193,11 +248,6 @@ gen(Node *n)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OEMPTY:
|
case OEMPTY:
|
||||||
// insert no-op so that
|
|
||||||
// L:; for { }
|
|
||||||
// does not treat L as a label for the loop.
|
|
||||||
if(lastlabel != L && lastlabel->label == p3)
|
|
||||||
gused(N);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OBLOCK:
|
case OBLOCK:
|
||||||
@ -205,13 +255,41 @@ gen(Node *n)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OLABEL:
|
case OLABEL:
|
||||||
newlab(OLABEL, n, n->right);
|
lab = newlab(n);
|
||||||
|
|
||||||
|
// if there are pending gotos, resolve them all to the current pc.
|
||||||
|
for(p1=lab->gotopc; p1; p1=p2) {
|
||||||
|
p2 = unpatch(p1);
|
||||||
|
patch(p1, pc);
|
||||||
|
}
|
||||||
|
lab->gotopc = P;
|
||||||
|
if(lab->labelpc == P)
|
||||||
|
lab->labelpc = pc;
|
||||||
|
|
||||||
|
if(n->right) {
|
||||||
|
switch(n->right->op) {
|
||||||
|
case OFOR:
|
||||||
|
case OSWITCH:
|
||||||
|
case OSELECT:
|
||||||
|
// so stmtlabel can find the label
|
||||||
|
n->right->sym = lab->sym;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OGOTO:
|
case OGOTO:
|
||||||
hasgoto = 1;
|
// if label is defined, emit jump to it.
|
||||||
newlab(OGOTO, n, N);
|
// otherwise save list of pending gotos in lab->gotopc.
|
||||||
gjmp(P);
|
// the list is linked through the normal jump target field
|
||||||
|
// to avoid a second list. (the jumps are actually still
|
||||||
|
// valid code, since they're just going to another goto
|
||||||
|
// to the same label. we'll unwind it when we learn the pc
|
||||||
|
// of the label in the OLABEL case above.)
|
||||||
|
lab = newlab(n);
|
||||||
|
if(lab->labelpc != P)
|
||||||
|
gjmp(lab->labelpc);
|
||||||
|
else
|
||||||
|
lab->gotopc = gjmp(lab->gotopc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OBREAK:
|
case OBREAK:
|
||||||
@ -266,12 +344,10 @@ gen(Node *n)
|
|||||||
continpc = pc;
|
continpc = pc;
|
||||||
|
|
||||||
// define break and continue labels
|
// define break and continue labels
|
||||||
if((lab = lastlabel) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n) {
|
if((lab = stmtlabel(n)) != L) {
|
||||||
lab->breakpc = breakpc;
|
lab->breakpc = breakpc;
|
||||||
lab->continpc = continpc;
|
lab->continpc = continpc;
|
||||||
} else
|
}
|
||||||
lab = L;
|
|
||||||
|
|
||||||
gen(n->nincr); // contin: incr
|
gen(n->nincr); // contin: incr
|
||||||
patch(p1, pc); // test:
|
patch(p1, pc); // test:
|
||||||
bgen(n->ntest, 0, breakpc); // if(!test) goto break
|
bgen(n->ntest, 0, breakpc); // if(!test) goto break
|
||||||
@ -304,10 +380,8 @@ gen(Node *n)
|
|||||||
breakpc = gjmp(P); // break: goto done
|
breakpc = gjmp(P); // break: goto done
|
||||||
|
|
||||||
// define break label
|
// define break label
|
||||||
if((lab = lastlabel) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n)
|
if((lab = stmtlabel(n)) != L)
|
||||||
lab->breakpc = breakpc;
|
lab->breakpc = breakpc;
|
||||||
else
|
|
||||||
lab = L;
|
|
||||||
|
|
||||||
patch(p1, pc); // test:
|
patch(p1, pc); // test:
|
||||||
genlist(n->nbody); // switch(test) body
|
genlist(n->nbody); // switch(test) body
|
||||||
@ -323,10 +397,8 @@ gen(Node *n)
|
|||||||
breakpc = gjmp(P); // break: goto done
|
breakpc = gjmp(P); // break: goto done
|
||||||
|
|
||||||
// define break label
|
// define break label
|
||||||
if((lab = lastlabel) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n)
|
if((lab = stmtlabel(n)) != L)
|
||||||
lab->breakpc = breakpc;
|
lab->breakpc = breakpc;
|
||||||
else
|
|
||||||
lab = L;
|
|
||||||
|
|
||||||
patch(p1, pc); // test:
|
patch(p1, pc); // test:
|
||||||
genlist(n->nbody); // select() body
|
genlist(n->nbody); // select() body
|
||||||
|
@ -278,6 +278,7 @@ struct Node
|
|||||||
int32 iota;
|
int32 iota;
|
||||||
};
|
};
|
||||||
#define N ((Node*)0)
|
#define N ((Node*)0)
|
||||||
|
EXTERN int32 walkgen;
|
||||||
|
|
||||||
struct NodeList
|
struct NodeList
|
||||||
{
|
{
|
||||||
@ -632,21 +633,20 @@ typedef struct Prog Prog;
|
|||||||
|
|
||||||
struct Label
|
struct Label
|
||||||
{
|
{
|
||||||
uchar op; // OGOTO/OLABEL
|
|
||||||
uchar used;
|
uchar used;
|
||||||
Sym* sym;
|
Sym* sym;
|
||||||
Node* stmt;
|
Node* def;
|
||||||
Prog* label; // pointer to code
|
NodeList* use;
|
||||||
|
Label* link;
|
||||||
|
|
||||||
|
// for use during gen
|
||||||
|
Prog* gotopc; // pointer to unresolved gotos
|
||||||
|
Prog* labelpc; // pointer to code
|
||||||
Prog* breakpc; // pointer to code
|
Prog* breakpc; // pointer to code
|
||||||
Prog* continpc; // pointer to code
|
Prog* continpc; // pointer to code
|
||||||
Label* link;
|
|
||||||
int32 lineno;
|
|
||||||
};
|
};
|
||||||
#define L ((Label*)0)
|
#define L ((Label*)0)
|
||||||
|
|
||||||
EXTERN Label* labellist;
|
|
||||||
EXTERN Label* lastlabel;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* note this is the runtime representation
|
* note this is the runtime representation
|
||||||
* of the compilers arrays.
|
* of the compilers arrays.
|
||||||
@ -691,6 +691,7 @@ EXTERN char* infile;
|
|||||||
EXTERN char* outfile;
|
EXTERN char* outfile;
|
||||||
EXTERN Biobuf* bout;
|
EXTERN Biobuf* bout;
|
||||||
EXTERN int nerrors;
|
EXTERN int nerrors;
|
||||||
|
EXTERN int nsavederrors;
|
||||||
EXTERN int nsyntaxerrors;
|
EXTERN int nsyntaxerrors;
|
||||||
EXTERN int safemode;
|
EXTERN int safemode;
|
||||||
EXTERN char namebuf[NSYMB];
|
EXTERN char namebuf[NSYMB];
|
||||||
@ -913,8 +914,8 @@ Type* pkgtype(Sym *s);
|
|||||||
void allocparams(void);
|
void allocparams(void);
|
||||||
void cgen_as(Node *nl, Node *nr);
|
void cgen_as(Node *nl, Node *nr);
|
||||||
void cgen_callmeth(Node *n, int proc);
|
void cgen_callmeth(Node *n, int proc);
|
||||||
void checklabels(void);
|
|
||||||
void clearlabels(void);
|
void clearlabels(void);
|
||||||
|
void checklabels(void);
|
||||||
int dotoffset(Node *n, int *oary, Node **nn);
|
int dotoffset(Node *n, int *oary, Node **nn);
|
||||||
void gen(Node *n);
|
void gen(Node *n);
|
||||||
void genlist(NodeList *l);
|
void genlist(NodeList *l);
|
||||||
@ -1132,6 +1133,7 @@ Type* ptrto(Type *t);
|
|||||||
void* remal(void *p, int32 on, int32 n);
|
void* remal(void *p, int32 on, int32 n);
|
||||||
Sym* restrictlookup(char *name, Pkg *pkg);
|
Sym* restrictlookup(char *name, Pkg *pkg);
|
||||||
Node* safeexpr(Node *n, NodeList **init);
|
Node* safeexpr(Node *n, NodeList **init);
|
||||||
|
void saveerrors(void);
|
||||||
Node* cheapexpr(Node *n, NodeList **init);
|
Node* cheapexpr(Node *n, NodeList **init);
|
||||||
int32 setlineno(Node *n);
|
int32 setlineno(Node *n);
|
||||||
void setmaxarg(Type *t);
|
void setmaxarg(Type *t);
|
||||||
@ -1252,11 +1254,10 @@ Plist* newplist(void);
|
|||||||
Node* nodarg(Type*, int);
|
Node* nodarg(Type*, int);
|
||||||
void nopout(Prog*);
|
void nopout(Prog*);
|
||||||
void patch(Prog*, Prog*);
|
void patch(Prog*, Prog*);
|
||||||
|
Prog* unpatch(Prog*);
|
||||||
void zfile(Biobuf *b, char *p, int n);
|
void zfile(Biobuf *b, char *p, int n);
|
||||||
void zhist(Biobuf *b, int line, vlong offset);
|
void zhist(Biobuf *b, int line, vlong offset);
|
||||||
void zname(Biobuf *b, Sym *s, int t);
|
void zname(Biobuf *b, Sym *s, int t);
|
||||||
void data(void);
|
void data(void);
|
||||||
void text(void);
|
void text(void);
|
||||||
|
|
||||||
EXTERN int hasgoto;
|
|
||||||
void clearstk(void);
|
|
||||||
|
@ -66,7 +66,7 @@ static void fixlbrace(int);
|
|||||||
%type <node> switch_stmt uexpr
|
%type <node> switch_stmt uexpr
|
||||||
%type <node> xfndcl typedcl
|
%type <node> xfndcl typedcl
|
||||||
|
|
||||||
%type <list> xdcl fnbody fnres switch_body loop_body dcl_name_list
|
%type <list> xdcl fnbody fnres loop_body dcl_name_list
|
||||||
%type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list
|
%type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list
|
||||||
%type <list> oexpr_list caseblock_list stmt_list oarg_type_list_ocomma arg_type_list
|
%type <list> oexpr_list caseblock_list stmt_list oarg_type_list_ocomma arg_type_list
|
||||||
%type <list> interfacedcl_list vardcl vardcl_list structdcl structdcl_list
|
%type <list> interfacedcl_list vardcl vardcl_list structdcl structdcl_list
|
||||||
@ -449,7 +449,7 @@ case:
|
|||||||
// will be converted to OCASE
|
// will be converted to OCASE
|
||||||
// right will point to next case
|
// right will point to next case
|
||||||
// done in casebody()
|
// done in casebody()
|
||||||
poptodcl();
|
markdcl();
|
||||||
$$ = nod(OXCASE, N, N);
|
$$ = nod(OXCASE, N, N);
|
||||||
$$->list = $2;
|
$$->list = $2;
|
||||||
if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
|
if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
|
||||||
@ -468,7 +468,7 @@ case:
|
|||||||
// will be converted to OCASE
|
// will be converted to OCASE
|
||||||
// right will point to next case
|
// right will point to next case
|
||||||
// done in casebody()
|
// done in casebody()
|
||||||
poptodcl();
|
markdcl();
|
||||||
$$ = nod(OXCASE, N, N);
|
$$ = nod(OXCASE, N, N);
|
||||||
if($2->next == nil)
|
if($2->next == nil)
|
||||||
n = nod(OAS, $2->n, $4);
|
n = nod(OAS, $2->n, $4);
|
||||||
@ -484,7 +484,7 @@ case:
|
|||||||
// will be converted to OCASE
|
// will be converted to OCASE
|
||||||
// right will point to next case
|
// right will point to next case
|
||||||
// done in casebody()
|
// done in casebody()
|
||||||
poptodcl();
|
markdcl();
|
||||||
$$ = nod(OXCASE, N, N);
|
$$ = nod(OXCASE, N, N);
|
||||||
$$->list = list1(colas($2, list1($4)));
|
$$->list = list1(colas($2, list1($4)));
|
||||||
}
|
}
|
||||||
@ -492,7 +492,7 @@ case:
|
|||||||
{
|
{
|
||||||
Node *n;
|
Node *n;
|
||||||
|
|
||||||
poptodcl();
|
markdcl();
|
||||||
$$ = nod(OXCASE, N, N);
|
$$ = nod(OXCASE, N, N);
|
||||||
if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
|
if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
|
||||||
// type switch - declare variable
|
// type switch - declare variable
|
||||||
@ -514,17 +514,6 @@ compound_stmt:
|
|||||||
popdcl();
|
popdcl();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch_body:
|
|
||||||
LBODY
|
|
||||||
{
|
|
||||||
markdcl();
|
|
||||||
}
|
|
||||||
caseblock_list '}'
|
|
||||||
{
|
|
||||||
$$ = $3;
|
|
||||||
popdcl();
|
|
||||||
}
|
|
||||||
|
|
||||||
caseblock:
|
caseblock:
|
||||||
case
|
case
|
||||||
{
|
{
|
||||||
@ -553,6 +542,7 @@ caseblock:
|
|||||||
yyerror("missing statement after label");
|
yyerror("missing statement after label");
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
$$->nbody = $3;
|
$$->nbody = $3;
|
||||||
|
popdcl();
|
||||||
}
|
}
|
||||||
|
|
||||||
caseblock_list:
|
caseblock_list:
|
||||||
@ -674,11 +664,11 @@ switch_stmt:
|
|||||||
n = N;
|
n = N;
|
||||||
typesw = nod(OXXX, typesw, n);
|
typesw = nod(OXXX, typesw, n);
|
||||||
}
|
}
|
||||||
switch_body
|
LBODY caseblock_list '}'
|
||||||
{
|
{
|
||||||
$$ = $3;
|
$$ = $3;
|
||||||
$$->op = OSWITCH;
|
$$->op = OSWITCH;
|
||||||
$$->list = $5;
|
$$->list = $6;
|
||||||
typesw = typesw->left;
|
typesw = typesw->left;
|
||||||
popdcl();
|
popdcl();
|
||||||
}
|
}
|
||||||
@ -686,15 +676,13 @@ switch_stmt:
|
|||||||
select_stmt:
|
select_stmt:
|
||||||
LSELECT
|
LSELECT
|
||||||
{
|
{
|
||||||
markdcl();
|
|
||||||
typesw = nod(OXXX, typesw, N);
|
typesw = nod(OXXX, typesw, N);
|
||||||
}
|
}
|
||||||
switch_body
|
LBODY caseblock_list '}'
|
||||||
{
|
{
|
||||||
$$ = nod(OSELECT, N, N);
|
$$ = nod(OSELECT, N, N);
|
||||||
$$->list = $3;
|
$$->list = $4;
|
||||||
typesw = typesw->left;
|
typesw = typesw->left;
|
||||||
popdcl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1474,13 +1462,19 @@ non_dcl_stmt:
|
|||||||
$$ = $1;
|
$$ = $1;
|
||||||
$$->nelse = list1($3);
|
$$->nelse = list1($3);
|
||||||
}
|
}
|
||||||
| labelname ':' stmt
|
| labelname ':'
|
||||||
|
{
|
||||||
|
$1 = nod(OLABEL, $1, N);
|
||||||
|
$1->sym = dclstack; // context, for goto restrictions
|
||||||
|
}
|
||||||
|
stmt
|
||||||
{
|
{
|
||||||
NodeList *l;
|
NodeList *l;
|
||||||
|
|
||||||
l = list1(nod(OLABEL, $1, $3));
|
$1->right = $4;
|
||||||
if($3)
|
l = list1($1);
|
||||||
l = list(l, $3);
|
if($4)
|
||||||
|
l = list(l, $4);
|
||||||
$$ = liststmt(l);
|
$$ = liststmt(l);
|
||||||
}
|
}
|
||||||
| LFALL
|
| LFALL
|
||||||
@ -1507,6 +1501,7 @@ non_dcl_stmt:
|
|||||||
| LGOTO new_name
|
| LGOTO new_name
|
||||||
{
|
{
|
||||||
$$ = nod(OGOTO, $2, N);
|
$$ = nod(OGOTO, $2, N);
|
||||||
|
$$->sym = dclstack; // context, for goto restrictions
|
||||||
}
|
}
|
||||||
| LRETURN oexpr_list
|
| LRETURN oexpr_list
|
||||||
{
|
{
|
||||||
|
@ -97,7 +97,7 @@ fault(int s)
|
|||||||
// in the program, don't bother complaining
|
// in the program, don't bother complaining
|
||||||
// about the seg fault too; let the user clean up
|
// about the seg fault too; let the user clean up
|
||||||
// the code and try again.
|
// the code and try again.
|
||||||
if(nerrors > 0)
|
if(nsavederrors + nerrors > 0)
|
||||||
errorexit();
|
errorexit();
|
||||||
fatal("fault");
|
fatal("fault");
|
||||||
}
|
}
|
||||||
@ -256,7 +256,10 @@ main(int argc, char *argv[])
|
|||||||
for(l=xtop; l; l=l->next)
|
for(l=xtop; l; l=l->next)
|
||||||
if(l->n->op == ODCLFUNC) {
|
if(l->n->op == ODCLFUNC) {
|
||||||
curfn = l->n;
|
curfn = l->n;
|
||||||
|
saveerrors();
|
||||||
typechecklist(l->n->nbody, Etop);
|
typechecklist(l->n->nbody, Etop);
|
||||||
|
if(nerrors != 0)
|
||||||
|
l->n->nbody = nil; // type errors; do not compile
|
||||||
}
|
}
|
||||||
curfn = nil;
|
curfn = nil;
|
||||||
|
|
||||||
@ -264,7 +267,7 @@ main(int argc, char *argv[])
|
|||||||
if(l->n->op == ODCLFUNC)
|
if(l->n->op == ODCLFUNC)
|
||||||
funccompile(l->n, 0);
|
funccompile(l->n, 0);
|
||||||
|
|
||||||
if(nerrors == 0)
|
if(nsavederrors+nerrors == 0)
|
||||||
fninit(xtop);
|
fninit(xtop);
|
||||||
|
|
||||||
while(closures) {
|
while(closures) {
|
||||||
@ -278,12 +281,12 @@ main(int argc, char *argv[])
|
|||||||
if(l->n->op == ONAME)
|
if(l->n->op == ONAME)
|
||||||
typecheck(&l->n, Erv);
|
typecheck(&l->n, Erv);
|
||||||
|
|
||||||
if(nerrors)
|
if(nerrors+nsavederrors)
|
||||||
errorexit();
|
errorexit();
|
||||||
|
|
||||||
dumpobj();
|
dumpobj();
|
||||||
|
|
||||||
if(nerrors)
|
if(nerrors+nsavederrors)
|
||||||
errorexit();
|
errorexit();
|
||||||
|
|
||||||
flusherrors();
|
flusherrors();
|
||||||
@ -291,6 +294,13 @@ main(int argc, char *argv[])
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
saveerrors(void)
|
||||||
|
{
|
||||||
|
nsavederrors += nerrors;
|
||||||
|
nerrors = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
arsize(Biobuf *b, char *name)
|
arsize(Biobuf *b, char *name)
|
||||||
{
|
{
|
||||||
|
@ -30,6 +30,8 @@ compile(Node *fn)
|
|||||||
if(fn->nbody == nil)
|
if(fn->nbody == nil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
saveerrors();
|
||||||
|
|
||||||
// set up domain for labels
|
// set up domain for labels
|
||||||
clearlabels();
|
clearlabels();
|
||||||
|
|
||||||
@ -53,7 +55,7 @@ compile(Node *fn)
|
|||||||
|
|
||||||
hasdefer = 0;
|
hasdefer = 0;
|
||||||
walk(curfn);
|
walk(curfn);
|
||||||
if(nerrors != 0 || isblank(curfn->nname))
|
if(nerrors != 0)
|
||||||
goto ret;
|
goto ret;
|
||||||
|
|
||||||
allocparams();
|
allocparams();
|
||||||
@ -67,7 +69,7 @@ compile(Node *fn)
|
|||||||
setlineno(curfn);
|
setlineno(curfn);
|
||||||
|
|
||||||
nodconst(&nod1, types[TINT32], 0);
|
nodconst(&nod1, types[TINT32], 0);
|
||||||
ptxt = gins(ATEXT, curfn->nname, &nod1);
|
ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
|
||||||
afunclit(&ptxt->from);
|
afunclit(&ptxt->from);
|
||||||
|
|
||||||
ginit();
|
ginit();
|
||||||
|
@ -2716,6 +2716,11 @@ typecheckdef(Node *n)
|
|||||||
default:
|
default:
|
||||||
fatal("typecheckdef %O", n->op);
|
fatal("typecheckdef %O", n->op);
|
||||||
|
|
||||||
|
case OGOTO:
|
||||||
|
case OLABEL:
|
||||||
|
// not really syms
|
||||||
|
break;
|
||||||
|
|
||||||
case OLITERAL:
|
case OLITERAL:
|
||||||
if(n->ntype != N) {
|
if(n->ntype != N) {
|
||||||
typecheck(&n->ntype, Etype);
|
typecheck(&n->ntype, Etype);
|
||||||
@ -2772,7 +2777,7 @@ typecheckdef(Node *n)
|
|||||||
if(n->defn == N) {
|
if(n->defn == N) {
|
||||||
if(n->etype != 0) // like OPRINTN
|
if(n->etype != 0) // like OPRINTN
|
||||||
break;
|
break;
|
||||||
if(nerrors > 0) {
|
if(nsavederrors+nerrors > 0) {
|
||||||
// Can have undefined variables in x := foo
|
// Can have undefined variables in x := foo
|
||||||
// that make x have an n->ndefn == nil.
|
// that make x have an n->ndefn == nil.
|
||||||
// If there are other errors anyway, don't
|
// If there are other errors anyway, don't
|
||||||
|
@ -19,4 +19,3 @@ const h bool = false
|
|||||||
const i int = 2
|
const i int = 2
|
||||||
const j float64 = 5
|
const j float64 = 5
|
||||||
|
|
||||||
func main() { println(a, b, c, d, e, f, g) }
|
|
||||||
|
@ -25,6 +25,6 @@ func main() {
|
|||||||
L1: // ERROR "statement"
|
L1: // ERROR "statement"
|
||||||
default:
|
default:
|
||||||
// correct since no semicolon is required before a '}'
|
// correct since no semicolon is required before a '}'
|
||||||
L2: // GCCGO_ERROR "not used"
|
L2: // ERROR "not used"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug344
|
// errchk $G -e $D/$F.go
|
||||||
|
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
@ -14,7 +14,9 @@ func main() {
|
|||||||
i := 42
|
i := 42
|
||||||
a := []*int{&i, &i, &i, &i}
|
a := []*int{&i, &i, &i, &i}
|
||||||
x := a[0]
|
x := a[0]
|
||||||
goto start
|
goto start // ERROR "goto start jumps into block"
|
||||||
|
z := 1
|
||||||
|
_ = z
|
||||||
for _, x = range a {
|
for _, x = range a {
|
||||||
start:
|
start:
|
||||||
fmt.Sprint(*x)
|
fmt.Sprint(*x)
|
||||||
|
Loading…
Reference in New Issue
Block a user