Skip to content

Commit 1087de6

Browse files
chenyukangcuviper
authored andcommitted
Fix the issue of unused assignment from MIR liveness checking
(cherry picked from commit 4930d3e)
1 parent 1c8bd26 commit 1087de6

File tree

3 files changed

+89
-9
lines changed

3 files changed

+89
-9
lines changed

compiler/rustc_mir_transform/src/liveness.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ struct Access {
4545
/// When we encounter multiple statements at the same location, we only increase the liveness,
4646
/// in order to avoid false positives.
4747
live: bool,
48+
/// Is this a direct access to the place itself, no projections, or to a field?
49+
/// This helps distinguish `x = ...` from `x.field = ...`
50+
is_direct: bool,
4851
}
4952

5053
#[tracing::instrument(level = "debug", skip(tcx), ret)]
@@ -689,15 +692,17 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
689692
|place: Place<'tcx>, kind, source_info: SourceInfo, live: &DenseBitSet<PlaceIndex>| {
690693
if let Some((index, extra_projections)) = checked_places.get(place.as_ref()) {
691694
if !is_indirect(extra_projections) {
695+
let is_direct = extra_projections.is_empty();
692696
match assignments[index].entry(source_info) {
693697
IndexEntry::Vacant(v) => {
694-
let access = Access { kind, live: live.contains(index) };
698+
let access = Access { kind, live: live.contains(index), is_direct };
695699
v.insert(access);
696700
}
697701
IndexEntry::Occupied(mut o) => {
698702
// There were already a sighting. Mark this statement as live if it
699703
// was, to avoid false positives.
700704
o.get_mut().live |= live.contains(index);
705+
o.get_mut().is_direct &= is_direct;
701706
}
702707
}
703708
}
@@ -781,7 +786,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
781786
continue;
782787
};
783788
let source_info = body.local_decls[place.local].source_info;
784-
let access = Access { kind, live: live.contains(index) };
789+
let access = Access { kind, live: live.contains(index), is_direct: true };
785790
assignments[index].insert(source_info, access);
786791
}
787792
}
@@ -1049,26 +1054,28 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
10491054

10501055
let Some((name, decl_span)) = self.checked_places.names[index] else { continue };
10511056

1052-
// We have outstanding assignments and with non-trivial drop.
1053-
// This is probably a drop-guard, so we do not issue a warning there.
1054-
if maybe_drop_guard(
1057+
let is_maybe_drop_guard = maybe_drop_guard(
10551058
tcx,
10561059
self.typing_env,
10571060
index,
10581061
&self.ever_dropped,
10591062
self.checked_places,
10601063
self.body,
1061-
) {
1062-
continue;
1063-
}
1064+
);
10641065

10651066
// We probed MIR in reverse order for dataflow.
10661067
// We revert the vector to give a consistent order to the user.
1067-
for (source_info, Access { live, kind }) in statements.into_iter().rev() {
1068+
for (source_info, Access { live, kind, is_direct }) in statements.into_iter().rev() {
10681069
if live {
10691070
continue;
10701071
}
10711072

1073+
// If this place was dropped and has non-trivial drop,
1074+
// skip reporting field assignments.
1075+
if !is_direct && is_maybe_drop_guard {
1076+
continue;
1077+
}
1078+
10721079
// Report the dead assignment.
10731080
let Some(hir_id) = source_info.scope.lint_root(&self.body.source_scopes) else {
10741081
continue;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//@ check-fail
2+
#![deny(unused)]
3+
4+
fn test_one_extra_assign() {
5+
let mut value = b"0".to_vec(); //~ ERROR value assigned to `value` is never read
6+
value = b"1".to_vec();
7+
println!("{:?}", value);
8+
}
9+
10+
fn test_two_extra_assign() {
11+
let mut x = 1; //~ ERROR value assigned to `x` is never read
12+
x = 2; //~ ERROR value assigned to `x` is never read
13+
x = 3;
14+
println!("{}", x);
15+
}
16+
17+
struct Point {
18+
x: i32,
19+
y: i32,
20+
}
21+
22+
fn test_indirect_assign() {
23+
let mut p = Point { x: 1, y: 1 }; //~ ERROR value assigned to `p` is never read
24+
p = Point { x: 2, y: 2 };
25+
p.x = 3;
26+
println!("{}", p.y);
27+
}
28+
29+
fn main() {
30+
test_one_extra_assign();
31+
test_two_extra_assign();
32+
test_indirect_assign();
33+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
error: value assigned to `value` is never read
2+
--> $DIR/unused-assign-148960.rs:5:21
3+
|
4+
LL | let mut value = b"0".to_vec();
5+
| ^^^^^^^^^^^^^
6+
|
7+
= help: maybe it is overwritten before being read?
8+
note: the lint level is defined here
9+
--> $DIR/unused-assign-148960.rs:2:9
10+
|
11+
LL | #![deny(unused)]
12+
| ^^^^^^
13+
= note: `#[deny(unused_assignments)]` implied by `#[deny(unused)]`
14+
15+
error: value assigned to `x` is never read
16+
--> $DIR/unused-assign-148960.rs:11:17
17+
|
18+
LL | let mut x = 1;
19+
| ^
20+
|
21+
= help: maybe it is overwritten before being read?
22+
23+
error: value assigned to `x` is never read
24+
--> $DIR/unused-assign-148960.rs:12:5
25+
|
26+
LL | x = 2;
27+
| ^^^^^
28+
|
29+
= help: maybe it is overwritten before being read?
30+
31+
error: value assigned to `p` is never read
32+
--> $DIR/unused-assign-148960.rs:23:17
33+
|
34+
LL | let mut p = Point { x: 1, y: 1 };
35+
| ^^^^^^^^^^^^^^^^^^^^
36+
|
37+
= help: maybe it is overwritten before being read?
38+
39+
error: aborting due to 4 previous errors
40+

0 commit comments

Comments
 (0)