Skip to content
/ rust Public
forked from rust-lang/rust

Commit 1e8fdf4

Browse files
committed
Auto merge of rust-lang#11320 - max-niederman:redundant_locals_shadow_mutated, r=Alexendoo
redundant_locals: fix FPs on mutated shadows Fixes rust-lang#11290. When a mutable binding is shadowed by a mutable binding of the same name in a different scope, mutations in that scope have different meaning. This PR fixes spurious `redundant_locals` emissions on such locals. cc `@Centri3,` `@flip1995` changelog: [`redundant_locals`]: fix false positives on mutated shadows
2 parents 8703661 + a5f62bd commit 1e8fdf4

File tree

3 files changed

+31
-11
lines changed

3 files changed

+31
-11
lines changed

clippy_lints/src/redundant_locals.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use clippy_utils::diagnostics::span_lint_and_help;
22
use clippy_utils::is_from_proc_macro;
33
use clippy_utils::ty::needs_ordered_drop;
4+
use rustc_ast::Mutability;
45
use rustc_hir::def::Res;
56
use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, HirId, Local, Node, Pat, PatKind, QPath};
67
use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -62,6 +63,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
6263
if let Node::Pat(binding_pat) = cx.tcx.hir().get(binding_id);
6364
// the previous binding has the same mutability
6465
if find_binding(binding_pat, ident).unwrap().1 == mutability;
66+
// the local does not change the effect of assignments to the binding. see #11290
67+
if !affects_assignments(cx, mutability, binding_id, local.hir_id);
6568
// the local does not affect the code's drop behavior
6669
if !affects_drop_behavior(cx, binding_id, local.hir_id, expr);
6770
// the local is user-controlled
@@ -94,6 +97,14 @@ fn find_binding(pat: &Pat<'_>, name: Ident) -> Option<BindingAnnotation> {
9497
ret
9598
}
9699

100+
/// Check if a rebinding of a local changes the effect of assignments to the binding.
101+
fn affects_assignments(cx: &LateContext<'_>, mutability: Mutability, bind: HirId, rebind: HirId) -> bool {
102+
let hir = cx.tcx.hir();
103+
104+
// the binding is mutable and the rebinding is in a different scope than the original binding
105+
mutability == Mutability::Mut && hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind)
106+
}
107+
97108
/// Check if a rebinding of a local affects the code's drop behavior.
98109
fn affects_drop_behavior<'tcx>(cx: &LateContext<'tcx>, bind: HirId, rebind: HirId, rebind_expr: &Expr<'tcx>) -> bool {
99110
let hir = cx.tcx.hir();

tests/ui/redundant_locals.rs

+9
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ fn downgraded_mutability() {
2727
let x = x;
2828
}
2929

30+
// see #11290
31+
fn shadow_mutation() {
32+
let mut x = 1;
33+
{
34+
let mut x = x;
35+
x = 2;
36+
}
37+
}
38+
3039
fn coercion(par: &mut i32) {
3140
let par: &i32 = par;
3241

tests/ui/redundant_locals.stderr

+11-11
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ LL | let mut x = x;
2020
= help: remove the redefinition of `x`
2121

2222
error: redundant redefinition of a binding
23-
--> $DIR/redundant_locals.rs:37:14
23+
--> $DIR/redundant_locals.rs:46:14
2424
|
2525
LL | fn parameter(x: i32) {
2626
| ^
@@ -30,7 +30,7 @@ LL | let x = x;
3030
= help: remove the redefinition of `x`
3131

3232
error: redundant redefinition of a binding
33-
--> $DIR/redundant_locals.rs:42:9
33+
--> $DIR/redundant_locals.rs:51:9
3434
|
3535
LL | let x = 1;
3636
| ^
@@ -40,7 +40,7 @@ LL | let x = x;
4040
= help: remove the redefinition of `x`
4141

4242
error: redundant redefinition of a binding
43-
--> $DIR/redundant_locals.rs:43:9
43+
--> $DIR/redundant_locals.rs:52:9
4444
|
4545
LL | let x = x;
4646
| ^
@@ -50,7 +50,7 @@ LL | let x = x;
5050
= help: remove the redefinition of `x`
5151

5252
error: redundant redefinition of a binding
53-
--> $DIR/redundant_locals.rs:44:9
53+
--> $DIR/redundant_locals.rs:53:9
5454
|
5555
LL | let x = x;
5656
| ^
@@ -60,7 +60,7 @@ LL | let x = x;
6060
= help: remove the redefinition of `x`
6161

6262
error: redundant redefinition of a binding
63-
--> $DIR/redundant_locals.rs:45:9
63+
--> $DIR/redundant_locals.rs:54:9
6464
|
6565
LL | let x = x;
6666
| ^
@@ -70,7 +70,7 @@ LL | let x = x;
7070
= help: remove the redefinition of `x`
7171

7272
error: redundant redefinition of a binding
73-
--> $DIR/redundant_locals.rs:50:9
73+
--> $DIR/redundant_locals.rs:59:9
7474
|
7575
LL | let a = 1;
7676
| ^
@@ -81,7 +81,7 @@ LL | let a = a;
8181
= help: remove the redefinition of `a`
8282

8383
error: redundant redefinition of a binding
84-
--> $DIR/redundant_locals.rs:51:9
84+
--> $DIR/redundant_locals.rs:60:9
8585
|
8686
LL | let b = 2;
8787
| ^
@@ -92,7 +92,7 @@ LL | let b = b;
9292
= help: remove the redefinition of `b`
9393

9494
error: redundant redefinition of a binding
95-
--> $DIR/redundant_locals.rs:58:13
95+
--> $DIR/redundant_locals.rs:67:13
9696
|
9797
LL | let x = 1;
9898
| ^
@@ -102,7 +102,7 @@ LL | let x = x;
102102
= help: remove the redefinition of `x`
103103

104104
error: redundant redefinition of a binding
105-
--> $DIR/redundant_locals.rs:65:13
105+
--> $DIR/redundant_locals.rs:74:13
106106
|
107107
LL | let x = 1;
108108
| ^
@@ -112,7 +112,7 @@ LL | let x = x;
112112
= help: remove the redefinition of `x`
113113

114114
error: redundant redefinition of a binding
115-
--> $DIR/redundant_locals.rs:68:6
115+
--> $DIR/redundant_locals.rs:77:6
116116
|
117117
LL | |x: i32| {
118118
| ^
@@ -122,7 +122,7 @@ LL | let x = x;
122122
= help: remove the redefinition of `x`
123123

124124
error: redundant redefinition of a binding
125-
--> $DIR/redundant_locals.rs:85:9
125+
--> $DIR/redundant_locals.rs:94:9
126126
|
127127
LL | let x = 1;
128128
| ^

0 commit comments

Comments
 (0)