aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/typecheck/typecheck.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/typecheck/typecheck.go')
-rw-r--r--src/cmd/compile/internal/typecheck/typecheck.go34
1 files changed, 34 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go
index 519d8ddfd9..4b5c3198ca 100644
--- a/src/cmd/compile/internal/typecheck/typecheck.go
+++ b/src/cmd/compile/internal/typecheck/typecheck.go
@@ -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 {