Skip to content

Commit 57c1dcf

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

File tree

3 files changed

+50
-7
lines changed

3 files changed

+50
-7
lines changed

compiler/rustc_mir_transform/src/liveness.rs

Lines changed: 26 additions & 7 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,9 +653,10 @@ 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) => {
@@ -742,7 +746,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
742746
continue;
743747
};
744748
let source_info = body.local_decls[place.local].source_info;
745-
let access = Access { kind, live: live.contains(index) };
749+
let access = Access { kind, live: live.contains(index), is_direct: true };
746750
assignments[index].insert(source_info, access);
747751
}
748752
}
@@ -1048,26 +1052,41 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
10481052

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

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(
1055+
let is_maybe_drop_guard = maybe_drop_guard(
10541056
tcx,
10551057
self.typing_env,
10561058
index,
10571059
&self.ever_dropped,
10581060
self.checked_places,
10591061
self.body,
1060-
) {
1062+
);
1063+
1064+
let is_pure_drop_guard = is_maybe_drop_guard && {
1065+
// Check if ALL direct assignments are not live
1066+
// which meaning the place is never read
1067+
statements
1068+
.values()
1069+
.filter(|access| access.kind == AccessKind::Assign && access.is_direct)
1070+
.all(|access| !access.live)
1071+
};
1072+
1073+
if is_pure_drop_guard {
10611074
continue;
10621075
}
10631076

10641077
// We probed MIR in reverse order for dataflow.
10651078
// We revert the vector to give a consistent order to the user.
1066-
for (source_info, Access { live, kind }) in statements.into_iter().rev() {
1079+
for (source_info, Access { live, kind, is_direct }) in statements.into_iter().rev() {
10671080
if live {
10681081
continue;
10691082
}
10701083

1084+
// If this place was dropped and has non-trivial drop,
1085+
// skip reporting field assignments.
1086+
if !is_direct && is_maybe_drop_guard {
1087+
continue;
1088+
}
1089+
10711090
// Report the dead assignment.
10721091
let Some(hir_id) = source_info.scope.lint_root(&self.body.source_scopes) else {
10731092
continue;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//@ check-fail
2+
#![deny(unused)]
3+
4+
fn main() {
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+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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: aborting due to 1 previous error
16+

0 commit comments

Comments
 (0)