mirror of
https://github.com/golang/go
synced 2024-11-02 11:50:30 +00:00
gc: detect type switch variable not used cases.
Fixes #873 Fixes #2162 R=rsc CC=golang-dev https://golang.org/cl/5341043
This commit is contained in:
parent
f2dc50b48d
commit
aac144b120
11 changed files with 82 additions and 31 deletions
|
@ -418,9 +418,7 @@ simple_stmt:
|
||||||
| expr_list LCOLAS expr_list
|
| expr_list LCOLAS expr_list
|
||||||
{
|
{
|
||||||
if($3->n->op == OTYPESW) {
|
if($3->n->op == OTYPESW) {
|
||||||
Node *n;
|
$$ = nod(OTYPESW, N, $3->n->right);
|
||||||
|
|
||||||
n = N;
|
|
||||||
if($3->next != nil)
|
if($3->next != nil)
|
||||||
yyerror("expr.(type) must be alone in list");
|
yyerror("expr.(type) must be alone in list");
|
||||||
if($1->next != nil)
|
if($1->next != nil)
|
||||||
|
@ -428,8 +426,7 @@ simple_stmt:
|
||||||
else if($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME)
|
else if($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME)
|
||||||
yyerror("invalid variable name %N in type switch", $1->n);
|
yyerror("invalid variable name %N in type switch", $1->n);
|
||||||
else
|
else
|
||||||
n = $1->n;
|
$$->left = dclname($1->n->sym); // it's a colas, so must not re-use an oldname.
|
||||||
$$ = nod(OTYPESW, n, $3->n->right);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$$ = colas($1, $3);
|
$$ = colas($1, $3);
|
||||||
|
@ -448,7 +445,7 @@ simple_stmt:
|
||||||
case:
|
case:
|
||||||
LCASE expr_or_type_list ':'
|
LCASE expr_or_type_list ':'
|
||||||
{
|
{
|
||||||
Node *n;
|
Node *n, *nn;
|
||||||
|
|
||||||
// will be converted to OCASE
|
// will be converted to OCASE
|
||||||
// right will point to next case
|
// right will point to next case
|
||||||
|
@ -458,12 +455,13 @@ case:
|
||||||
$$->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) {
|
||||||
// type switch - declare variable
|
// type switch - declare variable
|
||||||
n = newname(n->sym);
|
nn = newname(n->sym);
|
||||||
n->used = 1; // TODO(rsc): better job here
|
declare(nn, dclcontext);
|
||||||
declare(n, dclcontext);
|
$$->nname = nn;
|
||||||
$$->nname = n;
|
|
||||||
|
// keep track of the instances for reporting unused
|
||||||
|
nn->defn = typesw->right;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
| LCASE expr_or_type_list '=' expr ':'
|
| LCASE expr_or_type_list '=' expr ':'
|
||||||
{
|
{
|
||||||
|
@ -494,16 +492,18 @@ case:
|
||||||
}
|
}
|
||||||
| LDEFAULT ':'
|
| LDEFAULT ':'
|
||||||
{
|
{
|
||||||
Node *n;
|
Node *n, *nn;
|
||||||
|
|
||||||
markdcl();
|
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
|
||||||
n = newname(n->sym);
|
nn = newname(n->sym);
|
||||||
n->used = 1; // TODO(rsc): better job here
|
declare(nn, dclcontext);
|
||||||
declare(n, dclcontext);
|
$$->nname = nn;
|
||||||
$$->nname = n;
|
|
||||||
|
// keep track of the instances for reporting unused
|
||||||
|
nn->defn = typesw->right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,6 @@ walk(Node *fn)
|
||||||
{
|
{
|
||||||
char s[50];
|
char s[50];
|
||||||
NodeList *l;
|
NodeList *l;
|
||||||
Node *n;
|
|
||||||
int lno;
|
int lno;
|
||||||
|
|
||||||
curfn = fn;
|
curfn = fn;
|
||||||
|
@ -77,15 +76,33 @@ walk(Node *fn)
|
||||||
yyerror("function ends without a return statement");
|
yyerror("function ends without a return statement");
|
||||||
|
|
||||||
lno = lineno;
|
lno = lineno;
|
||||||
|
|
||||||
|
// Final typecheck for any unused variables.
|
||||||
|
// It's hard to be on the heap when not-used, but best to be consistent about &~PHEAP here and below.
|
||||||
|
for(l=fn->dcl; l; l=l->next)
|
||||||
|
if(l->n->op == ONAME && (l->n->class&~PHEAP) == PAUTO)
|
||||||
|
typecheck(&l->n, Erv | Easgn);
|
||||||
|
|
||||||
|
// Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
|
||||||
|
for(l=fn->dcl; l; l=l->next)
|
||||||
|
if(l->n->op == ONAME && (l->n->class&~PHEAP) == PAUTO && l->n->defn && l->n->defn->op == OTYPESW && l->n->used)
|
||||||
|
l->n->defn->left->used++;
|
||||||
|
|
||||||
for(l=fn->dcl; l; l=l->next) {
|
for(l=fn->dcl; l; l=l->next) {
|
||||||
n = l->n;
|
if(l->n->op != ONAME || (l->n->class&~PHEAP) != PAUTO || l->n->sym->name[0] == '&' || l->n->used)
|
||||||
if(n->op != ONAME || n->class != PAUTO)
|
|
||||||
continue;
|
continue;
|
||||||
lineno = n->lineno;
|
if(l->n->defn && l->n->defn->op == OTYPESW) {
|
||||||
typecheck(&n, Erv | Easgn); // only needed for unused variables
|
if(l->n->defn->left->used)
|
||||||
if(!n->used && n->sym->name[0] != '&' && !nsyntaxerrors)
|
continue;
|
||||||
yyerror("%S declared and not used", n->sym);
|
lineno = l->n->defn->left->lineno;
|
||||||
}
|
yyerror("%S declared and not used", l->n->sym);
|
||||||
|
l->n->defn->left->used = 1; // suppress repeats
|
||||||
|
} else {
|
||||||
|
lineno = l->n->lineno;
|
||||||
|
yyerror("%S declared and not used", l->n->sym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lineno = lno;
|
lineno = lno;
|
||||||
if(nerrors != 0)
|
if(nerrors != 0)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -617,7 +617,7 @@ func (p *Parser) Skip() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
switch t := tok.(type) {
|
switch tok.(type) {
|
||||||
case StartElement:
|
case StartElement:
|
||||||
if err := p.Skip(); err != nil {
|
if err := p.Skip(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -131,7 +131,7 @@ func (x Const) Match(y Const) (u, v Const) {
|
||||||
// otherwise the result is invalid.
|
// otherwise the result is invalid.
|
||||||
func (x Const) Convert(typ *Type) Const {
|
func (x Const) Convert(typ *Type) Const {
|
||||||
// TODO(gri) implement this
|
// TODO(gri) implement this
|
||||||
switch x := x.val.(type) {
|
switch x.val.(type) {
|
||||||
case bool:
|
case bool:
|
||||||
case *big.Int:
|
case *big.Int:
|
||||||
case *big.Rat:
|
case *big.Rat:
|
||||||
|
|
|
@ -1131,7 +1131,7 @@ func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
|
||||||
|
|
||||||
// checkExpr checks that x is an expression (and not a type).
|
// checkExpr checks that x is an expression (and not a type).
|
||||||
func (p *parser) checkExpr(x ast.Expr) ast.Expr {
|
func (p *parser) checkExpr(x ast.Expr) ast.Expr {
|
||||||
switch t := unparen(x).(type) {
|
switch unparen(x).(type) {
|
||||||
case *ast.BadExpr:
|
case *ast.BadExpr:
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
case *ast.BasicLit:
|
case *ast.BasicLit:
|
||||||
|
|
|
@ -20,7 +20,7 @@ type Getter interface {
|
||||||
|
|
||||||
func f1(p Empty) {
|
func f1(p Empty) {
|
||||||
switch x := p.(type) {
|
switch x := p.(type) {
|
||||||
default: println("failed to match interface"); os.Exit(1);
|
default: println("failed to match interface", x); os.Exit(1);
|
||||||
case Getter: break;
|
case Getter: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ func main() {
|
||||||
// and worse, compiled the wrong code
|
// and worse, compiled the wrong code
|
||||||
// for one of them.
|
// for one of them.
|
||||||
var x interface{};
|
var x interface{};
|
||||||
switch v := x.(type) {
|
switch x.(type) {
|
||||||
case func(int):
|
case func(int):
|
||||||
case func(f int): // ERROR "duplicate"
|
case func(f int): // ERROR "duplicate"
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
package main
|
package main
|
||||||
func main() {
|
func main() {
|
||||||
var v interface{} = 0;
|
var v interface{} = 0;
|
||||||
switch x := v.(type) {
|
switch v.(type) {
|
||||||
case int:
|
case int:
|
||||||
fallthrough; // ERROR "fallthrough"
|
fallthrough; // ERROR "fallthrough"
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -80,7 +80,7 @@ func main() {
|
||||||
case 2:
|
case 2:
|
||||||
i = 3.14
|
i = 3.14
|
||||||
}
|
}
|
||||||
switch k := i.(type) {
|
switch i.(type) {
|
||||||
case p0.T:
|
case p0.T:
|
||||||
if j != 0 {
|
if j != 0 {
|
||||||
println("type switch p0.T")
|
println("type switch p0.T")
|
||||||
|
|
|
@ -15,5 +15,7 @@ func foo(t interface{}, c chan int) {
|
||||||
case <-c:
|
case <-c:
|
||||||
// bug was: internal compiler error: var without type, init: v
|
// bug was: internal compiler error: var without type, init: v
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
_ = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
32
test/fixedbugs/bug373.go
Normal file
32
test/fixedbugs/bug373.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// errchk $G $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.
|
||||||
|
|
||||||
|
// Issue 873, 2162
|
||||||
|
|
||||||
|
package foo
|
||||||
|
|
||||||
|
func f(x interface{}) {
|
||||||
|
switch t := x.(type) { // ERROR "declared and not used"
|
||||||
|
case int:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func g(x interface{}) {
|
||||||
|
switch t := x.(type) {
|
||||||
|
case int:
|
||||||
|
case float32:
|
||||||
|
println(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func h(x interface{}) {
|
||||||
|
switch t := x.(type) {
|
||||||
|
case int:
|
||||||
|
case float32:
|
||||||
|
default:
|
||||||
|
println(t)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue