gc: diagnose unused labels
R=ken2 CC=golang-dev https://golang.org/cl/4287047
This commit is contained in:
parent
e72156b316
commit
66f09fd459
@ -32,7 +32,7 @@ compile(Node *fn)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// set up domain for labels
|
// set up domain for labels
|
||||||
labellist = L;
|
clearlabels();
|
||||||
|
|
||||||
lno = setlineno(fn);
|
lno = setlineno(fn);
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ compile(Node *fn)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// set up domain for labels
|
// set up domain for labels
|
||||||
labellist = L;
|
clearlabels();
|
||||||
|
|
||||||
lno = setlineno(fn);
|
lno = setlineno(fn);
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ compile(Node *fn)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// set up domain for labels
|
// set up domain for labels
|
||||||
labellist = L;
|
clearlabels();
|
||||||
|
|
||||||
lno = setlineno(fn);
|
lno = setlineno(fn);
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ dflag(void)
|
|||||||
/*
|
/*
|
||||||
* declaration stack & operations
|
* declaration stack & operations
|
||||||
*/
|
*/
|
||||||
static Sym* dclstack;
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dcopy(Sym *a, Sym *b)
|
dcopy(Sym *a, Sym *b)
|
||||||
|
147
src/cmd/gc/gen.c
147
src/cmd/gc/gen.c
@ -64,62 +64,83 @@ allocparams(void)
|
|||||||
lineno = lno;
|
lineno = lno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clearlabels(void)
|
||||||
|
{
|
||||||
|
Label *l;
|
||||||
|
|
||||||
|
for(l=labellist; l!=L; l=l->link)
|
||||||
|
l->sym->label = L;
|
||||||
|
|
||||||
|
labellist = L;
|
||||||
|
lastlabel = L;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
newlab(int op, Sym *s, Node *stmt)
|
newlab(int op, Node *nlab, Node *stmt)
|
||||||
{
|
{
|
||||||
Label *lab;
|
Label *lab;
|
||||||
|
Sym *s;
|
||||||
|
int32 lno;
|
||||||
|
|
||||||
|
s = nlab->left->sym;
|
||||||
|
lno = nlab->left->lineno;
|
||||||
|
|
||||||
lab = mal(sizeof(*lab));
|
lab = mal(sizeof(*lab));
|
||||||
lab->link = labellist;
|
if(lastlabel == nil)
|
||||||
labellist = lab;
|
labellist = lab;
|
||||||
|
else
|
||||||
|
lastlabel->link = lab;
|
||||||
|
lastlabel = lab;
|
||||||
|
|
||||||
|
lab->lineno = lno;
|
||||||
lab->sym = s;
|
lab->sym = s;
|
||||||
lab->op = op;
|
lab->op = op;
|
||||||
lab->label = pc;
|
lab->label = pc;
|
||||||
lab->stmt = stmt;
|
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, *m;
|
Label *l;
|
||||||
Sym *s;
|
Sym *s;
|
||||||
|
int lno;
|
||||||
|
|
||||||
// // print the label list
|
lno = lineno;
|
||||||
// for(l=labellist; l!=L; l=l->link) {
|
|
||||||
// print("lab %O %S\n", l->op, l->sym);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
// resolve goto using syms
|
||||||
for(l=labellist; l!=L; l=l->link) {
|
for(l=labellist; l!=L; l=l->link) {
|
||||||
switch(l->op) {
|
switch(l->op) {
|
||||||
case OLABEL:
|
|
||||||
// these are definitions -
|
|
||||||
s = l->sym;
|
|
||||||
for(m=labellist; m!=L; m=m->link) {
|
|
||||||
if(m->sym != s)
|
|
||||||
continue;
|
|
||||||
switch(m->op) {
|
|
||||||
case OLABEL:
|
|
||||||
// these are definitions -
|
|
||||||
// look for redefinitions
|
|
||||||
if(l != m)
|
|
||||||
yyerror("label %S redefined", s);
|
|
||||||
break;
|
|
||||||
case OGOTO:
|
case OGOTO:
|
||||||
// these are references -
|
s = l->sym;
|
||||||
// patch to definition
|
if(s->label == L) {
|
||||||
patch(m->label, l->label);
|
lineno = l->lineno;
|
||||||
m->sym = S; // mark done
|
yyerror("label %S not defined", s);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
s->label->used = 1;
|
||||||
|
patch(l->label, s->label->label);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// diagnostic for all undefined references
|
// diagnose unused labels
|
||||||
for(l=labellist; l!=L; l=l->link)
|
for(l=labellist; l!=L; l=l->link) {
|
||||||
if(l->op == OGOTO && l->sym != S)
|
if(l->op == OLABEL && !l->used) {
|
||||||
yyerror("label %S not defined", l->sym);
|
lineno = l->lineno;
|
||||||
|
yyerror("label %S defined and not used", l->sym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lineno = lno;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -171,7 +192,7 @@ gen(Node *n)
|
|||||||
// insert no-op so that
|
// insert no-op so that
|
||||||
// L:; for { }
|
// L:; for { }
|
||||||
// does not treat L as a label for the loop.
|
// does not treat L as a label for the loop.
|
||||||
if(labellist && labellist->label == p3)
|
if(lastlabel != L && lastlabel->label == p3)
|
||||||
gused(N);
|
gused(N);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -180,57 +201,56 @@ gen(Node *n)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OLABEL:
|
case OLABEL:
|
||||||
newlab(OLABEL, n->left->sym, n->right);
|
newlab(OLABEL, n, n->right);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OGOTO:
|
case OGOTO:
|
||||||
newlab(OGOTO, n->left->sym, N);
|
newlab(OGOTO, n, N);
|
||||||
gjmp(P);
|
gjmp(P);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OBREAK:
|
case OBREAK:
|
||||||
if(n->left != N) {
|
if(n->left != N) {
|
||||||
for(lab=labellist; lab!=L; lab=lab->link) {
|
lab = n->left->sym->label;
|
||||||
if(lab->sym == n->left->sym) {
|
if(lab == L) {
|
||||||
if(lab->breakpc == P)
|
|
||||||
yyerror("invalid break label %S", n->left->sym);
|
|
||||||
gjmp(lab->breakpc);
|
|
||||||
goto donebreak;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(lab == L)
|
|
||||||
yyerror("break label not defined: %S", n->left->sym);
|
yyerror("break label not defined: %S", n->left->sym);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
lab->used = 1;
|
||||||
|
if(lab->breakpc == P) {
|
||||||
|
yyerror("invalid break label %S", n->left->sym);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gjmp(lab->breakpc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if(breakpc == P) {
|
if(breakpc == P) {
|
||||||
yyerror("break is not in a loop");
|
yyerror("break is not in a loop");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gjmp(breakpc);
|
gjmp(breakpc);
|
||||||
donebreak:
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OCONTINUE:
|
case OCONTINUE:
|
||||||
if(n->left != N) {
|
if(n->left != N) {
|
||||||
for(lab=labellist; lab!=L; lab=lab->link) {
|
lab = n->left->sym->label;
|
||||||
if(lab->sym == n->left->sym) {
|
if(lab == L) {
|
||||||
if(lab->continpc == P)
|
|
||||||
yyerror("invalid continue label %S", n->left->sym);
|
|
||||||
gjmp(lab->continpc);
|
|
||||||
goto donecont;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(lab == L)
|
|
||||||
yyerror("continue label not defined: %S", n->left->sym);
|
yyerror("continue label not defined: %S", n->left->sym);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
lab->used = 1;
|
||||||
|
if(lab->continpc == P) {
|
||||||
|
yyerror("invalid continue label %S", n->left->sym);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gjmp(lab->continpc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if(continpc == P) {
|
if(continpc == P) {
|
||||||
yyerror("continue is not in a loop");
|
yyerror("continue is not in a loop");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gjmp(continpc);
|
gjmp(continpc);
|
||||||
donecont:
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OFOR:
|
case OFOR:
|
||||||
@ -241,10 +261,11 @@ gen(Node *n)
|
|||||||
continpc = pc;
|
continpc = pc;
|
||||||
|
|
||||||
// define break and continue labels
|
// define break and continue labels
|
||||||
if((lab = labellist) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n) {
|
if((lab = lastlabel) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n) {
|
||||||
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:
|
||||||
@ -254,6 +275,10 @@ gen(Node *n)
|
|||||||
patch(breakpc, pc); // done:
|
patch(breakpc, pc); // done:
|
||||||
continpc = scontin;
|
continpc = scontin;
|
||||||
breakpc = sbreak;
|
breakpc = sbreak;
|
||||||
|
if(lab) {
|
||||||
|
lab->breakpc = P;
|
||||||
|
lab->continpc = P;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OIF:
|
case OIF:
|
||||||
@ -274,13 +299,17 @@ gen(Node *n)
|
|||||||
breakpc = gjmp(P); // break: goto done
|
breakpc = gjmp(P); // break: goto done
|
||||||
|
|
||||||
// define break label
|
// define break label
|
||||||
if((lab = labellist) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n)
|
if((lab = lastlabel) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n)
|
||||||
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
|
||||||
patch(breakpc, pc); // done:
|
patch(breakpc, pc); // done:
|
||||||
breakpc = sbreak;
|
breakpc = sbreak;
|
||||||
|
if(lab != L)
|
||||||
|
lab->breakpc = P;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OSELECT:
|
case OSELECT:
|
||||||
@ -289,13 +318,17 @@ gen(Node *n)
|
|||||||
breakpc = gjmp(P); // break: goto done
|
breakpc = gjmp(P); // break: goto done
|
||||||
|
|
||||||
// define break label
|
// define break label
|
||||||
if((lab = labellist) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n)
|
if((lab = lastlabel) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n)
|
||||||
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
|
||||||
patch(breakpc, pc); // done:
|
patch(breakpc, pc); // done:
|
||||||
breakpc = sbreak;
|
breakpc = sbreak;
|
||||||
|
if(lab != L)
|
||||||
|
lab->breakpc = P;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OASOP:
|
case OASOP:
|
||||||
|
@ -138,6 +138,7 @@ typedef struct Sym Sym;
|
|||||||
typedef struct Node Node;
|
typedef struct Node Node;
|
||||||
typedef struct NodeList NodeList;
|
typedef struct NodeList NodeList;
|
||||||
typedef struct Type Type;
|
typedef struct Type Type;
|
||||||
|
typedef struct Label Label;
|
||||||
|
|
||||||
struct Type
|
struct Type
|
||||||
{
|
{
|
||||||
@ -302,11 +303,14 @@ struct Sym
|
|||||||
Pkg* pkg;
|
Pkg* pkg;
|
||||||
char* name; // variable name
|
char* name; // variable name
|
||||||
Node* def; // definition: ONAME OTYPE OPACK or OLITERAL
|
Node* def; // definition: ONAME OTYPE OPACK or OLITERAL
|
||||||
|
Label* label; // corresponding label (ephemeral)
|
||||||
int32 block; // blocknumber to catch redeclaration
|
int32 block; // blocknumber to catch redeclaration
|
||||||
int32 lastlineno; // last declaration for diagnostic
|
int32 lastlineno; // last declaration for diagnostic
|
||||||
};
|
};
|
||||||
#define S ((Sym*)0)
|
#define S ((Sym*)0)
|
||||||
|
|
||||||
|
EXTERN Sym* dclstack;
|
||||||
|
|
||||||
struct Pkg
|
struct Pkg
|
||||||
{
|
{
|
||||||
char* name;
|
char* name;
|
||||||
@ -619,20 +623,22 @@ struct Magic
|
|||||||
|
|
||||||
typedef struct Prog Prog;
|
typedef struct Prog Prog;
|
||||||
|
|
||||||
typedef struct Label Label;
|
|
||||||
struct Label
|
struct Label
|
||||||
{
|
{
|
||||||
uchar op; // OGOTO/OLABEL
|
uchar op; // OGOTO/OLABEL
|
||||||
|
uchar used;
|
||||||
Sym* sym;
|
Sym* sym;
|
||||||
Node* stmt;
|
Node* stmt;
|
||||||
Prog* label; // pointer to code
|
Prog* label; // 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;
|
Label* link;
|
||||||
|
int32 lineno;
|
||||||
};
|
};
|
||||||
#define L ((Label*)0)
|
#define L ((Label*)0)
|
||||||
|
|
||||||
EXTERN Label* labellist;
|
EXTERN Label* labellist;
|
||||||
|
EXTERN Label* lastlabel;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* note this is the runtime representation
|
* note this is the runtime representation
|
||||||
@ -900,6 +906,7 @@ 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 checklabels(void);
|
||||||
|
void clearlabels(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);
|
||||||
|
60
test/label.go
Normal file
60
test/label.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// errchk $G -e $D/$F.go
|
||||||
|
|
||||||
|
// Copyright 2011 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.
|
||||||
|
|
||||||
|
// Pass 1 label errors.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
var x int
|
||||||
|
|
||||||
|
func f() {
|
||||||
|
L1: // ERROR "label L1 defined and not used"
|
||||||
|
for {
|
||||||
|
}
|
||||||
|
L2: // ERROR "label L2 defined and not used"
|
||||||
|
select {
|
||||||
|
}
|
||||||
|
L3: // ERROR "label L3 defined and not used"
|
||||||
|
switch {
|
||||||
|
}
|
||||||
|
L4: // ERROR "label L4 defined and not used"
|
||||||
|
if true {
|
||||||
|
}
|
||||||
|
L5: // ERROR "label L5 defined and not used"
|
||||||
|
f()
|
||||||
|
L6:
|
||||||
|
f()
|
||||||
|
L6: // ERROR "label L6 already defined at"
|
||||||
|
f()
|
||||||
|
if x == 20 {
|
||||||
|
goto L6
|
||||||
|
}
|
||||||
|
|
||||||
|
L7:
|
||||||
|
for {
|
||||||
|
break L7
|
||||||
|
}
|
||||||
|
|
||||||
|
L8:
|
||||||
|
for {
|
||||||
|
if x == 21 {
|
||||||
|
continue L8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
L9:
|
||||||
|
switch {
|
||||||
|
case true:
|
||||||
|
break L9
|
||||||
|
defalt: // ERROR "label defalt defined and not used"
|
||||||
|
}
|
||||||
|
|
||||||
|
L10:
|
||||||
|
select {
|
||||||
|
default:
|
||||||
|
break L10
|
||||||
|
}
|
||||||
|
}
|
85
test/label1.go
Normal file
85
test/label1.go
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// errchk $G -e $D/$F.go
|
||||||
|
|
||||||
|
// Copyright 2011 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.
|
||||||
|
|
||||||
|
// Pass 2 label errors.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
var x int
|
||||||
|
|
||||||
|
func f() {
|
||||||
|
L1:
|
||||||
|
for {
|
||||||
|
if x == 0 {
|
||||||
|
break L1
|
||||||
|
}
|
||||||
|
if x == 1 {
|
||||||
|
continue L1
|
||||||
|
}
|
||||||
|
goto L1
|
||||||
|
}
|
||||||
|
|
||||||
|
L2:
|
||||||
|
select {
|
||||||
|
default:
|
||||||
|
if x == 0 {
|
||||||
|
break L2
|
||||||
|
}
|
||||||
|
if x == 1 {
|
||||||
|
continue L2 // ERROR "invalid continue label L2"
|
||||||
|
}
|
||||||
|
goto L2
|
||||||
|
}
|
||||||
|
|
||||||
|
L3:
|
||||||
|
switch {
|
||||||
|
case x > 10:
|
||||||
|
if x == 11 {
|
||||||
|
break L3
|
||||||
|
}
|
||||||
|
if x == 12 {
|
||||||
|
continue L3 // ERROR "invalid continue label L3"
|
||||||
|
}
|
||||||
|
goto L3
|
||||||
|
}
|
||||||
|
|
||||||
|
L4:
|
||||||
|
if true {
|
||||||
|
if x == 13 {
|
||||||
|
break L4 // ERROR "invalid break label L4"
|
||||||
|
}
|
||||||
|
if x == 14 {
|
||||||
|
continue L4 // ERROR "invalid continue label L4"
|
||||||
|
}
|
||||||
|
if x == 15 {
|
||||||
|
goto L4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
L5:
|
||||||
|
f()
|
||||||
|
if x == 16 {
|
||||||
|
break L5 // ERROR "invalid break label L5"
|
||||||
|
}
|
||||||
|
if x == 17 {
|
||||||
|
continue L5 // ERROR "invalid continue label L5"
|
||||||
|
}
|
||||||
|
if x == 18 {
|
||||||
|
goto L5
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
if x == 19 {
|
||||||
|
break L1 // ERROR "invalid break label L1"
|
||||||
|
}
|
||||||
|
if x == 20 {
|
||||||
|
continue L1 // ERROR "invalid continue label L1"
|
||||||
|
}
|
||||||
|
if x == 21 {
|
||||||
|
goto L1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user