Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(501)

Unified Diff: src/cmd/gc/gen.c

Issue 4641044: code review 4641044: gc: implement goto restriction (Closed)
Patch Set: diff -r a18d74ce4b78 https://go.googlecode.com/hg/ Created 13 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/cmd/gc/dcl.c ('k') | src/cmd/gc/go.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/cmd/gc/gen.c
===================================================================
--- a/src/cmd/gc/gen.c
+++ b/src/cmd/gc/gen.c
@@ -11,6 +11,10 @@
static void cgen_dcl(Node *n);
static void cgen_proc(Node *n, int proc);
+static void checkgoto(Node*, Node*);
+
+static Label *labellist;
+static Label *lastlabel;
Node*
sysfunc(char *name)
@@ -80,71 +84,122 @@
lastlabel = L;
}
-static void
-newlab(int op, Node *nlab, Node *stmt)
+static Label*
+newlab(Node *n)
{
+ Sym *s;
Label *lab;
- Sym *s;
- int32 lno;
- s = nlab->left->sym;
- lno = nlab->left->lineno;
+ s = n->left->sym;
+ 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));
- 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;
- }
+ return lab;
}
void
checklabels(void)
{
- Label *l;
- Sym *s;
+ Label *lab;
+ 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;
- lno = lineno;
-
- // resolve goto using syms
- for(l=labellist; l!=L; l=l->link) {
- switch(l->op) {
- case OGOTO:
- s = l->sym;
- if(s->label == L) {
- lineno = l->lineno;
- yyerror("label %S not defined", s);
- break;
- }
- s->label->used = 1;
- patch(l->label, s->label->label);
- break;
+ 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;
+ 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)
+ 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;
}
-
- // 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);
- }
- }
-
- 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 @@
break;
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;
case OBLOCK:
@@ -205,13 +255,41 @@
break;
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;
case OGOTO:
- hasgoto = 1;
- newlab(OGOTO, n, N);
- gjmp(P);
+ // if label is defined, emit jump to it.
+ // otherwise save list of pending gotos in lab->gotopc.
+ // 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;
case OBREAK:
@@ -266,12 +344,10 @@
continpc = pc;
// 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->continpc = continpc;
- } else
- lab = L;
-
+ }
gen(n->nincr); // contin: incr
patch(p1, pc); // test:
bgen(n->ntest, 0, breakpc); // if(!test) goto break
@@ -304,10 +380,8 @@
breakpc = gjmp(P); // break: goto done
// define break label
- if((lab = lastlabel) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n)
+ if((lab = stmtlabel(n)) != L)
lab->breakpc = breakpc;
- else
- lab = L;
patch(p1, pc); // test:
genlist(n->nbody); // switch(test) body
@@ -323,10 +397,8 @@
breakpc = gjmp(P); // break: goto done
// define break label
- if((lab = lastlabel) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n)
+ if((lab = stmtlabel(n)) != L)
lab->breakpc = breakpc;
- else
- lab = L;
patch(p1, pc); // test:
genlist(n->nbody); // select() body
« no previous file with comments | « src/cmd/gc/dcl.c ('k') | src/cmd/gc/go.h » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b