1
0
mirror of https://github.com/golang/go synced 2024-11-22 02:14:40 -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:
Russ Cox 2011-06-17 15:25:05 -04:00
parent e852202f37
commit 7f4c5ea7d8
16 changed files with 269 additions and 134 deletions

View File

@ -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;

View File

@ -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.
*/ */

View File

@ -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;

View File

@ -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.
*/ */

View File

@ -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;

View File

@ -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.
*/ */

View File

@ -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;

View File

@ -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,71 +84,122 @@ 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; s = n->left->sym;
lno = nlab->left->lineno; if((lab = s->label) == L) {
lab = mal(sizeof(*lab));
if(lastlabel == nil)
labellist = lab;
else
lastlabel->link = lab;
lastlabel = lab;
lab->sym = s;
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);
lab = mal(sizeof(*lab)); return lab;
if(lastlabel == nil)
labellist = lab;
else
lastlabel->link = lab;
lastlabel = lab;
lab->lineno = lno;
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;
}
} }
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;
lno = lineno; if(from->sym == to->sym)
return;
// resolve goto using syms
for(l=labellist; l!=L; l=l->link) { nf = 0;
switch(l->op) { for(fs=from->sym; fs; fs=fs->link)
case OGOTO: nf++;
s = l->sym; nt = 0;
if(s->label == L) { for(fs=to->sym; fs; fs=fs->link)
lineno = l->lineno; nt++;
yyerror("label %S not defined", s); fs = from->sym;
break; for(; nf > nt; nf--)
} fs = fs->link;
s->label->used = 1; if(fs != to->sym) {
patch(l->label, s->label->label); lno = lineno;
break; setlineno(from);
// decide what to complain about.
// prefer to complain about 'into block' over declarations,
// so scan backward to find most recent block or else dcl.
block = S;
dcl = S;
ts = to->sym;
for(; nt > nf; nt--) {
if(ts->pkg == nil)
block = ts;
else
dcl = ts;
ts = ts->link;
} }
} while(ts != fs) {
if(ts->pkg == nil)
// diagnose unused labels block = ts;
for(l=labellist; l!=L; l=l->link) { else
if(l->op == OLABEL && !l->used) { dcl = ts;
lineno = l->lineno; ts = ts->link;
yyerror("label %S defined and not used", l->sym); 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;
} }
/* /*
@ -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

View File

@ -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);

View File

@ -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
{ {

View File

@ -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)
{ {

View File

@ -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();

View File

@ -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

View File

@ -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) }

View File

@ -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"
} }
} }

View File

@ -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)