]> Cypherpunks repositories - gostls13.git/commitdiff
gc: detect type switch variable not used cases.
authorLuuk van Dijk <lvd@golang.org>
Fri, 4 Nov 2011 16:03:50 +0000 (17:03 +0100)
committerLuuk van Dijk <lvd@golang.org>
Fri, 4 Nov 2011 16:03:50 +0000 (17:03 +0100)
Fixes #873
Fixes #2162

R=rsc
CC=golang-dev
https://golang.org/cl/5341043

src/cmd/gc/go.y
src/cmd/gc/walk.c
src/pkg/encoding/xml/read.go
src/pkg/exp/types/const.go
src/pkg/go/parser/parser.go
test/fixedbugs/bug141.go
test/fixedbugs/bug200.go
test/fixedbugs/bug213.go
test/fixedbugs/bug248.dir/bug2.go
test/fixedbugs/bug309.go
test/fixedbugs/bug373.go [new file with mode: 0644]

index c349567f87364405999927dcd7997ede913c34f7..31ffc6d5baa350b52bd3011e3b73bf3e9a6701c8 100644 (file)
@@ -418,9 +418,7 @@ simple_stmt:
 |      expr_list LCOLAS expr_list
        {
                if($3->n->op == OTYPESW) {
-                       Node *n;
-                       
-                       n = N;
+                       $$ = nod(OTYPESW, N, $3->n->right);
                        if($3->next != nil)
                                yyerror("expr.(type) must be alone in list");
                        if($1->next != nil)
@@ -428,8 +426,7 @@ simple_stmt:
                        else if($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME)
                                yyerror("invalid variable name %N in type switch", $1->n);
                        else
-                               n = $1->n;
-                       $$ = nod(OTYPESW, n, $3->n->right);
+                               $$->left = dclname($1->n->sym);  // it's a colas, so must not re-use an oldname.
                        break;
                }
                $$ = colas($1, $3);
@@ -448,7 +445,7 @@ simple_stmt:
 case:
        LCASE expr_or_type_list ':'
        {
-               Node *n;
+               Node *n, *nn;
 
                // will be converted to OCASE
                // right will point to next case
@@ -458,12 +455,13 @@ case:
                $$->list = $2;
                if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
                        // type switch - declare variable
-                       n = newname(n->sym);
-                       n->used = 1;    // TODO(rsc): better job here
-                       declare(n, dclcontext);
-                       $$->nname = n;
+                       nn = newname(n->sym);
+                       declare(nn, dclcontext);
+                       $$->nname = nn;
+
+                       // keep track of the instances for reporting unused
+                       nn->defn = typesw->right;
                }
-               break;
        }
 |      LCASE expr_or_type_list '=' expr ':'
        {
@@ -494,16 +492,18 @@ case:
        }
 |      LDEFAULT ':'
        {
-               Node *n;
+               Node *n, *nn;
 
                markdcl();
                $$ = nod(OXCASE, N, N);
                if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
                        // type switch - declare variable
-                       n = newname(n->sym);
-                       n->used = 1;    // TODO(rsc): better job here
-                       declare(n, dclcontext);
-                       $$->nname = n;
+                       nn = newname(n->sym);
+                       declare(nn, dclcontext);
+                       $$->nname = nn;
+
+                       // keep track of the instances for reporting unused
+                       nn->defn = typesw->right;
                }
        }
 
index 9ff4aedec3f0e26456afce8ad2fd4cd798e81ac8..373c1eef2206c4b4c11bad163e627ef364ceba69 100644 (file)
@@ -63,7 +63,6 @@ walk(Node *fn)
 {
        char s[50];
        NodeList *l;
-       Node *n;
        int lno;
 
        curfn = fn;
@@ -77,15 +76,33 @@ walk(Node *fn)
                        yyerror("function ends without a return statement");
 
        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) {
-               n = l->n;
-               if(n->op != ONAME || n->class != PAUTO)
+               if(l->n->op != ONAME || (l->n->class&~PHEAP) != PAUTO || l->n->sym->name[0] == '&' || l->n->used)
                        continue;
-               lineno = n->lineno;
-               typecheck(&n, Erv | Easgn);     // only needed for unused variables
-               if(!n->used && n->sym->name[0] != '&' && !nsyntaxerrors)
-                       yyerror("%S declared and not used", n->sym);
-       }
+               if(l->n->defn && l->n->defn->op == OTYPESW) {
+                       if(l->n->defn->left->used)
+                               continue;
+                       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;
        if(nerrors != 0)
                return;
index a88941c92b3f593ff7a2220573a0d5ff2f004896..e97abec55a4490103fd6732a9781282dd2139445 100644 (file)
@@ -617,7 +617,7 @@ func (p *Parser) Skip() error {
                if err != nil {
                        return err
                }
-               switch t := tok.(type) {
+               switch tok.(type) {
                case StartElement:
                        if err := p.Skip(); err != nil {
                                return err
index 1ef95d9f952ef955f68d2e53cdd9815af2e01259..7b0e35566f265d42940c20d2e0fd4bd21f1517e9 100644 (file)
@@ -131,7 +131,7 @@ func (x Const) Match(y Const) (u, v Const) {
 // otherwise the result is invalid.
 func (x Const) Convert(typ *Type) Const {
        // TODO(gri) implement this
-       switch x := x.val.(type) {
+       switch x.val.(type) {
        case bool:
        case *big.Int:
        case *big.Rat:
index e2c944137217893adac3fe64d5b14f7d639c7e88..55b8998b7d585b8035bb8e615d00b87cfda2e1ec 100644 (file)
@@ -1131,7 +1131,7 @@ func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
 
 // checkExpr checks that x is an expression (and not a type).
 func (p *parser) checkExpr(x ast.Expr) ast.Expr {
-       switch t := unparen(x).(type) {
+       switch unparen(x).(type) {
        case *ast.BadExpr:
        case *ast.Ident:
        case *ast.BasicLit:
index 756ba308d9c3e20411ed7a208a6f938d17503bb1..1b125e5d1ee4bd265e7921b3a7a1e78c8a35d5ba 100644 (file)
@@ -20,7 +20,7 @@ type Getter interface {
 
 func f1(p Empty) {
        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;
        }
 
index 123f6872805bd8f3452a6e31b4f93ddf9e5feb6b..63b8633bd9fca5ccfa4bb7b551bf488cba9a1336 100644 (file)
@@ -12,7 +12,7 @@ func main() {
        // and worse, compiled the wrong code
        // for one of them.
        var x interface{};
-       switch v := x.(type) {
+       switch x.(type) {
        case func(int):
        case func(f int):       // ERROR "duplicate"
        }
index 07d9f9029d043ce0111b4849df0a369c511ad6d4..4d81dbb4de440df45052acade8ea6e4fcd739768 100644 (file)
@@ -7,7 +7,7 @@
 package main
 func main() {
        var v interface{} = 0;
-       switch x := v.(type) {
+       switch v.(type) {
        case int:
                fallthrough;            // ERROR "fallthrough"
        default:
index b6c816a5cef0fe99f6851868f9e99c9618ac0614..adce3667708f62c689dc4206d0a947ff2b493527 100644 (file)
@@ -80,7 +80,7 @@ func main() {
                case 2:
                        i = 3.14
                }
-               switch k := i.(type) {
+               switch i.(type) {
                case p0.T:
                        if j != 0 {
                                println("type switch p0.T")
index 07bebae74c17e8e1144f43e1411576687048a407..d893916cd96ad5552402de20ff1675c63a368f84 100644 (file)
@@ -15,5 +15,7 @@ func foo(t interface{}, c chan int) {
                case <-c:
                        // bug was: internal compiler error: var without type, init: v
                }
+       default:
+               _ = v
        }
 }
diff --git a/test/fixedbugs/bug373.go b/test/fixedbugs/bug373.go
new file mode 100644 (file)
index 0000000..934a6c7
--- /dev/null
@@ -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)
+       }
+}