Skip to content

Commit 4930d3e

Browse files
committed
Fix the issue of unused assignment from MIR liveness checking
1 parent 67c4cf3 commit 4930d3e

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)]
@@ -650,15 +653,17 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
650653
|place: Place<'tcx>, kind, source_info: SourceInfo, live: &DenseBitSet<PlaceIndex>| {
651654
if let Some((index, extra_projections)) = checked_places.get(place.as_ref()) {
652655
if !is_indirect(extra_projections) {
656+
let is_direct = extra_projections.is_empty();
653657
match assignments[index].entry(source_info) {
654658
IndexEntry::Vacant(v) => {
655-
let access = Access { kind, live: live.contains(index) };
659+
let access = Access { kind, live: live.contains(index), is_direct };
656660
v.insert(access);
657661
}
658662
IndexEntry::Occupied(mut o) => {
659663
// There were already a sighting. Mark this statement as live if it
660664
// was, to avoid false positives.
661665
o.get_mut().live |= live.contains(index);
666+
o.get_mut().is_direct &= is_direct;
662667
}
663668
}
664669
}
@@ -742,7 +747,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
742747
continue;
743748
};
744749
let source_info = body.local_decls[place.local].source_info;
745-
let access = Access { kind, live: live.contains(index) };
750+
let access = Access { kind, live: live.contains(index), is_direct: true };
746751
assignments[index].insert(source_info, access);
747752
}
748753
}
@@ -1048,26 +1053,28 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
10481053

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

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

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

1072+
// If this place was dropped and has non-trivial drop,
1073+
// skip reporting field assignments.
1074+
if !is_direct && is_maybe_drop_guard {
1075+
continue;
1076+
}
1077+
10711078
// Report the dead assignment.
10721079
let Some(hir_id) = source_info.scope.lint_root(&self.body.source_scopes) else {
10731080
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)