Flag redundant range clauses.
diff --git a/lint.go b/lint.go
index 347209b..64e8049 100644
--- a/lint.go
+++ b/lint.go
@@ -69,6 +69,7 @@
 	f.lintNames()
 	f.lintVarDecls()
 	f.lintElses()
+	f.lintRanges()
 
 	return f.problems
 }
@@ -577,6 +578,28 @@
 	})
 }
 
+// lintRanges examines range clauses. It complains about redundant constructions.
+func (f *file) lintRanges() {
+	f.walk(func(node ast.Node) bool {
+		rs, ok := node.(*ast.RangeStmt)
+		if !ok {
+			return true
+		}
+		if rs.Value == nil {
+			// for x = range m { ... }
+			return true // single var form
+		}
+		if !isIdent(rs.Value, "_") {
+			// for ?, y = range m { ... }
+			return true
+		}
+
+		f.errorf(rs.Value, 1, "should omit 2nd value from range; this loop is equivalent to `for %s %s range ...`", f.render(rs.Key), rs.Tok)
+
+		return true
+	})
+}
+
 func receiverName(fn *ast.FuncDecl) string {
 	switch e := fn.Recv.List[0].Type.(type) {
 	case *ast.Ident:
diff --git a/testdata/range.go b/testdata/range.go
new file mode 100644
index 0000000..e8629ed
--- /dev/null
+++ b/testdata/range.go
@@ -0,0 +1,27 @@
+// Test for range construction.
+
+// Package foo ...
+package foo
+
+func f() {
+	// with :=
+	for x, _ := range m { // MATCH /should omit 2nd value.*range.*equivalent.*for x := range/
+	}
+	// with =
+	for y, _ = range m { // MATCH /should omit 2nd value.*range.*equivalent.*for y = range/
+	}
+
+	// all OK:
+	for x := range m {
+	}
+	for x, y := range m {
+	}
+	for _, y := range m {
+	}
+	for x = range m {
+	}
+	for x, y = range m {
+	}
+	for _, y = range m {
+	}
+}