]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.regabi] cmd/compile: report unused variables during typecheck
authorMatthew Dempsky <mdempsky@google.com>
Fri, 1 Jan 2021 05:32:52 +0000 (21:32 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Fri, 1 Jan 2021 10:52:10 +0000 (10:52 +0000)
Unused variables are a type-checking error, so they should be reported
during typecheck rather than walk.

One catch is that we only want to report unused-variable errors for
functions that type check successfully, but some errors are reported
during noding, so we don't have an easy way to detect that
currently. As an approximate solution, we simply check if we've
reported any errors yet.

Passes toolstash -cmp.

Change-Id: I9400bfc94312c71d0c908a491e85c16d62224c9c
Reviewed-on: https://go-review.googlesource.com/c/go/+/280973
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
src/cmd/compile/internal/typecheck/typecheck.go
src/cmd/compile/internal/walk/walk.go

index 519d8ddfd95053a4fb3031682db262e19487266b..4b5c3198caccf66f3385a3771b9200347260ec41 100644 (file)
@@ -171,6 +171,7 @@ func FuncBody(n *ir.Func) {
        decldepth = 1
        errorsBefore := base.Errors()
        Stmts(n.Body)
+       CheckUnused(n)
        CheckReturn(n)
        if base.Errors() > errorsBefore {
                n.Body.Set(nil) // type errors; do not compile
@@ -2203,6 +2204,39 @@ func isTermNode(n ir.Node) bool {
        return false
 }
 
+// CheckUnused checks for any declared variables that weren't used.
+func CheckUnused(fn *ir.Func) {
+       // Only report unused variables if we haven't seen any type-checking
+       // errors yet.
+       if base.Errors() != 0 {
+               return
+       }
+
+       // Propagate the used flag for typeswitch variables up to the NONAME in its definition.
+       for _, ln := range fn.Dcl {
+               if ln.Op() == ir.ONAME && ln.Class_ == ir.PAUTO && ln.Used() {
+                       if guard, ok := ln.Defn.(*ir.TypeSwitchGuard); ok {
+                               guard.Used = true
+                       }
+               }
+       }
+
+       for _, ln := range fn.Dcl {
+               if ln.Op() != ir.ONAME || ln.Class_ != ir.PAUTO || ln.Used() {
+                       continue
+               }
+               if defn, ok := ln.Defn.(*ir.TypeSwitchGuard); ok {
+                       if defn.Used {
+                               continue
+                       }
+                       base.ErrorfAt(defn.Tag.Pos(), "%v declared but not used", ln.Sym())
+                       defn.Used = true // suppress repeats
+               } else {
+                       base.ErrorfAt(ln.Pos(), "%v declared but not used", ln.Sym())
+               }
+       }
+}
+
 // CheckReturn makes sure that fn terminates appropriately.
 func CheckReturn(fn *ir.Func) {
        if fn.Type().NumResults() != 0 && len(fn.Body) != 0 {
index b6be949689e581671bd10819ef3a945f31ed2aae..25f53a8e7c50c1cc63dac8aefa75fd063d6a92d4 100644 (file)
@@ -37,36 +37,6 @@ func Walk(fn *ir.Func) {
 
        lno := base.Pos
 
-       // Final typecheck for any unused variables.
-       for i, ln := range fn.Dcl {
-               if ln.Op() == ir.ONAME && (ln.Class_ == ir.PAUTO || ln.Class_ == ir.PAUTOHEAP) {
-                       ln = typecheck.AssignExpr(ln).(*ir.Name)
-                       fn.Dcl[i] = ln
-               }
-       }
-
-       // Propagate the used flag for typeswitch variables up to the NONAME in its definition.
-       for _, ln := range fn.Dcl {
-               if ln.Op() == ir.ONAME && (ln.Class_ == ir.PAUTO || ln.Class_ == ir.PAUTOHEAP) && ln.Defn != nil && ln.Defn.Op() == ir.OTYPESW && ln.Used() {
-                       ln.Defn.(*ir.TypeSwitchGuard).Used = true
-               }
-       }
-
-       for _, ln := range fn.Dcl {
-               if ln.Op() != ir.ONAME || (ln.Class_ != ir.PAUTO && ln.Class_ != ir.PAUTOHEAP) || ln.Sym().Name[0] == '&' || ln.Used() {
-                       continue
-               }
-               if defn, ok := ln.Defn.(*ir.TypeSwitchGuard); ok {
-                       if defn.Used {
-                               continue
-                       }
-                       base.ErrorfAt(defn.Tag.Pos(), "%v declared but not used", ln.Sym())
-                       defn.Used = true // suppress repeats
-               } else {
-                       base.ErrorfAt(ln.Pos(), "%v declared but not used", ln.Sym())
-               }
-       }
-
        base.Pos = lno
        if base.Errors() > errorsBefore {
                return