diff options
Diffstat (limited to 'src/cmd/compile/internal/typecheck/typecheck.go')
-rw-r--r-- | src/cmd/compile/internal/typecheck/typecheck.go | 34 |
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 { |