Skip to content

Commit 2f8b1e3

Browse files
needless_pass_by_ref_mut: Fix corner case in async functions
1 parent cdd6336 commit 2f8b1e3

File tree

4 files changed

+84
-6
lines changed

4 files changed

+84
-6
lines changed

clippy_lints/src/needless_pass_by_ref_mut.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
185185
}
186186
// Collect variables mutably used and spans which will need dereferencings from the
187187
// function body.
188-
let MutablyUsedVariablesCtxt { mutably_used_vars, .. } = {
188+
let mutably_used_vars = {
189189
let mut ctx = MutablyUsedVariablesCtxt {
190190
mutably_used_vars: HirIdSet::default(),
191191
prev_bind: None,
@@ -217,7 +217,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
217217
check_closures(&mut ctx, cx, &infcx, &mut checked_closures, async_closures);
218218
}
219219
}
220-
ctx
220+
ctx.generate_mutably_used_ids_from_aliases()
221221
};
222222
for ((&input, &_), arg) in it {
223223
// Only take `&mut` arguments.
@@ -309,12 +309,22 @@ struct MutablyUsedVariablesCtxt<'tcx> {
309309
}
310310

311311
impl<'tcx> MutablyUsedVariablesCtxt<'tcx> {
312-
fn add_mutably_used_var(&mut self, mut used_id: HirId) {
313-
while let Some(id) = self.aliases.get(&used_id) {
312+
fn add_mutably_used_var(&mut self, used_id: HirId) {
313+
self.mutably_used_vars.insert(used_id);
314+
}
315+
316+
// Because the alias may come after the mutable use of a variable, we need to fill the map at
317+
// the end.
318+
fn generate_mutably_used_ids_from_aliases(mut self) -> HirIdSet {
319+
let all_ids = self.mutably_used_vars.iter().copied().collect::<Vec<_>>();
320+
for mut used_id in all_ids {
321+
while let Some(id) = self.aliases.get(&used_id) {
322+
self.mutably_used_vars.insert(used_id);
323+
used_id = *id;
324+
}
314325
self.mutably_used_vars.insert(used_id);
315-
used_id = *id;
316326
}
317-
self.mutably_used_vars.insert(used_id);
327+
self.mutably_used_vars
318328
}
319329

320330
fn would_be_alias_cycle(&self, alias: HirId, mut target: HirId) -> bool {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// If both `inner_async3` and `inner_async4` are present, aliases are declared after
2+
// they're used in `inner_async4` for some reasons... This test ensures that no
3+
// only `v` is marked as not used mutably in `inner_async4`.
4+
5+
#![allow(clippy::redundant_closure_call)]
6+
#![warn(clippy::needless_pass_by_ref_mut)]
7+
8+
pub async fn inner_async3(x: &i32, y: &mut u32) {
9+
//~^ ERROR: this argument is a mutable reference, but not used mutably
10+
async {
11+
*y += 1;
12+
}
13+
.await;
14+
}
15+
16+
pub async fn inner_async4(u: &mut i32, v: &u32) {
17+
//~^ ERROR: this argument is a mutable reference, but not used mutably
18+
async {
19+
*u += 1;
20+
}
21+
.await;
22+
}
23+
24+
fn main() {}

tests/ui/needless_pass_by_ref_mut2.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// If both `inner_async3` and `inner_async4` are present, aliases are declared after
2+
// they're used in `inner_async4` for some reasons... This test ensures that no
3+
// only `v` is marked as not used mutably in `inner_async4`.
4+
5+
#![allow(clippy::redundant_closure_call)]
6+
#![warn(clippy::needless_pass_by_ref_mut)]
7+
8+
pub async fn inner_async3(x: &mut i32, y: &mut u32) {
9+
//~^ ERROR: this argument is a mutable reference, but not used mutably
10+
async {
11+
*y += 1;
12+
}
13+
.await;
14+
}
15+
16+
pub async fn inner_async4(u: &mut i32, v: &mut u32) {
17+
//~^ ERROR: this argument is a mutable reference, but not used mutably
18+
async {
19+
*u += 1;
20+
}
21+
.await;
22+
}
23+
24+
fn main() {}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: this argument is a mutable reference, but not used mutably
2+
--> tests/ui/needless_pass_by_ref_mut2.rs:8:30
3+
|
4+
LL | pub async fn inner_async3(x: &mut i32, y: &mut u32) {
5+
| ^^^^^^^^ help: consider changing to: `&i32`
6+
|
7+
= warning: changing this function will impact semver compatibility
8+
= note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
9+
= help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
10+
11+
error: this argument is a mutable reference, but not used mutably
12+
--> tests/ui/needless_pass_by_ref_mut2.rs:16:43
13+
|
14+
LL | pub async fn inner_async4(u: &mut i32, v: &mut u32) {
15+
| ^^^^^^^^ help: consider changing to: `&u32`
16+
|
17+
= warning: changing this function will impact semver compatibility
18+
19+
error: aborting due to 2 previous errors
20+

0 commit comments

Comments
 (0)