Skip to content

Commit 7a9f3b9

Browse files
committed
Auto merge of #156425 - chenyukang:yukang-fix-156416-unused-assignments-diverging, r=<try>
Fix unused assignments in diverging branches
2 parents 4b0c9d7 + 3996441 commit 7a9f3b9

3 files changed

Lines changed: 155 additions & 30 deletions

File tree

compiler/rustc_mir_transform/src/liveness.rs

Lines changed: 71 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ enum CaptureKind {
4040
struct Access {
4141
/// Describe the current access.
4242
kind: AccessKind,
43+
/// MIR location where this access happens.
44+
location: Location,
4345
/// Is the accessed place is live at the current statement?
4446
/// When we encounter multiple statements at the same location, we only increase the liveness,
4547
/// in order to avoid false positives.
@@ -648,26 +650,30 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
648650
&checked_places.places,
649651
);
650652

651-
let mut check_place =
652-
|place: Place<'tcx>, kind, source_info: SourceInfo, live: &DenseBitSet<PlaceIndex>| {
653-
if let Some((index, extra_projections)) = checked_places.get(place.as_ref()) {
654-
if !is_indirect(extra_projections) {
655-
let is_direct = extra_projections.is_empty();
656-
match assignments[index].entry(source_info) {
657-
IndexEntry::Vacant(v) => {
658-
let access = Access { kind, live: live.contains(index), is_direct };
659-
v.insert(access);
660-
}
661-
IndexEntry::Occupied(mut o) => {
662-
// There were already a sighting. Mark this statement as live if it
663-
// was, to avoid false positives.
664-
o.get_mut().live |= live.contains(index);
665-
o.get_mut().is_direct &= is_direct;
666-
}
653+
let mut check_place = |place: Place<'tcx>,
654+
kind,
655+
source_info: SourceInfo,
656+
location: Location,
657+
live: &DenseBitSet<PlaceIndex>| {
658+
if let Some((index, extra_projections)) = checked_places.get(place.as_ref()) {
659+
if !is_indirect(extra_projections) {
660+
let is_direct = extra_projections.is_empty();
661+
match assignments[index].entry(source_info) {
662+
IndexEntry::Vacant(v) => {
663+
let access =
664+
Access { kind, location, live: live.contains(index), is_direct };
665+
v.insert(access);
666+
}
667+
IndexEntry::Occupied(mut o) => {
668+
// There were already a sighting. Mark this statement as live if it
669+
// was, to avoid false positives.
670+
o.get_mut().live |= live.contains(index);
671+
o.get_mut().is_direct &= is_direct;
667672
}
668673
}
669674
}
670-
};
675+
}
676+
};
671677

672678
let mut record_drop = |place: Place<'tcx>| {
673679
if let Some((index, &[])) = checked_places.get(place.as_ref()) {
@@ -684,7 +690,13 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
684690
match &terminator.kind {
685691
TerminatorKind::Call { destination: place, .. }
686692
| TerminatorKind::Yield { resume_arg: place, .. } => {
687-
check_place(*place, AccessKind::Assign, terminator.source_info, live);
693+
check_place(
694+
*place,
695+
AccessKind::Assign,
696+
terminator.source_info,
697+
body.terminator_loc(bb),
698+
live,
699+
);
688700
record_drop(*place)
689701
}
690702
TerminatorKind::Drop { place, .. } => record_drop(*place),
@@ -693,21 +705,34 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
693705
if let InlineAsmOperand::Out { place: Some(place), .. }
694706
| InlineAsmOperand::InOut { out_place: Some(place), .. } = operand
695707
{
696-
check_place(*place, AccessKind::Assign, terminator.source_info, live);
708+
check_place(
709+
*place,
710+
AccessKind::Assign,
711+
terminator.source_info,
712+
body.terminator_loc(bb),
713+
live,
714+
);
697715
}
698716
}
699717
}
700718
_ => {}
701719
}
702720

703721
for (statement_index, statement) in bb_data.statements.iter().enumerate().rev() {
704-
cursor.seek_before_primary_effect(Location { block: bb, statement_index });
722+
let location = Location { block: bb, statement_index };
723+
cursor.seek_before_primary_effect(location);
705724
let live = cursor.get();
706725
ever_live.union(live);
707726
match &statement.kind {
708727
StatementKind::Assign(box (place, _))
709728
| StatementKind::SetDiscriminant { box place, .. } => {
710-
check_place(*place, AccessKind::Assign, statement.source_info, live);
729+
check_place(
730+
*place,
731+
AccessKind::Assign,
732+
statement.source_info,
733+
location,
734+
live,
735+
);
711736
}
712737
StatementKind::StorageLive(_)
713738
| StatementKind::StorageDead(_)
@@ -745,7 +770,12 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
745770
continue;
746771
};
747772
let source_info = body.local_decls[place.local].source_info;
748-
let access = Access { kind, live: live.contains(index), is_direct: true };
773+
let access = Access {
774+
kind,
775+
location: Location::START,
776+
live: live.contains(index),
777+
is_direct: true,
778+
};
749779
assignments[index].insert(source_info, access);
750780
}
751781
}
@@ -1098,23 +1128,34 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
10981128
continue;
10991129
}
11001130

1101-
let mut next_direct_assign = None;
1131+
let mut next_direct_assignments: Vec<(Span, Location)> = Vec::new();
11021132
let mut dead_statements = Vec::with_capacity(statements.len());
11031133

1104-
for (source_info, Access { live, kind, is_direct }) in statements.into_iter() {
1105-
let overwrite = match (kind, is_direct, next_direct_assign) {
1106-
(AccessKind::Assign, true, Some(overwrite_span)) => {
1107-
Some(errors::UnusedAssignOverwrite {
1134+
for (source_info, Access { live, kind, is_direct, location }) in statements.into_iter()
1135+
{
1136+
let overwrite = if kind == AccessKind::Assign && is_direct {
1137+
next_direct_assignments
1138+
.iter()
1139+
.filter(|(_, overwrite_location)| {
1140+
location.is_predecessor_of(*overwrite_location, self.body)
1141+
})
1142+
// MIR traversal order is not always source-nearest for assignments such
1143+
// as compound assignment operations.
1144+
.min_by_key(|(overwrite_span, _)| {
1145+
let is_source_successor = source_info.span.lo() <= overwrite_span.lo();
1146+
(!is_source_successor, overwrite_span.lo())
1147+
})
1148+
.map(|&(overwrite_span, _)| errors::UnusedAssignOverwrite {
11081149
assigned_span: source_info.span,
11091150
overwrite_span,
11101151
name,
11111152
})
1112-
}
1113-
_ => None,
1153+
} else {
1154+
None
11141155
};
11151156

11161157
if kind == AccessKind::Assign && is_direct {
1117-
next_direct_assign = Some(source_info.span);
1158+
next_direct_assignments.push((source_info.span, location));
11181159
}
11191160

11201161
if live {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//@ run-pass
2+
#![allow(dead_code)]
3+
#![warn(unused_assignments)]
4+
5+
fn diverging_else() {
6+
let x;
7+
if true {
8+
x = 42;
9+
} else {
10+
x = 35;
11+
//~^ WARN value assigned to `x` is never read
12+
panic!();
13+
}
14+
println!("{x}");
15+
}
16+
17+
fn diverging_match_arm() {
18+
let x;
19+
match true {
20+
false => {
21+
x = 35;
22+
//~^ WARN value assigned to `x` is never read
23+
panic!();
24+
}
25+
true => x = 42,
26+
}
27+
println!("{x}");
28+
}
29+
30+
fn real_overwrite_after_if(cond: bool) {
31+
let mut x;
32+
if cond {
33+
x = 35;
34+
//~^ WARN value assigned to `x` is never read
35+
} else {
36+
x = 42;
37+
//~^ WARN value assigned to `x` is never read
38+
}
39+
x = 99;
40+
println!("{x}");
41+
}
42+
43+
fn main() {}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
warning: value assigned to `x` is never read
2+
--> $DIR/unused-assignments-diverging-branch-issue-156416.rs:10:9
3+
|
4+
LL | x = 35;
5+
| ^^^^^^
6+
|
7+
= help: maybe it is overwritten before being read?
8+
note: the lint level is defined here
9+
--> $DIR/unused-assignments-diverging-branch-issue-156416.rs:3:9
10+
|
11+
LL | #![warn(unused_assignments)]
12+
| ^^^^^^^^^^^^^^^^^^
13+
14+
warning: value assigned to `x` is never read
15+
--> $DIR/unused-assignments-diverging-branch-issue-156416.rs:21:13
16+
|
17+
LL | x = 35;
18+
| ^^^^^^
19+
|
20+
= help: maybe it is overwritten before being read?
21+
22+
warning: value assigned to `x` is never read
23+
--> $DIR/unused-assignments-diverging-branch-issue-156416.rs:36:9
24+
|
25+
LL | x = 42;
26+
| ^^^^^^ this value is reassigned later and never used
27+
...
28+
LL | x = 99;
29+
| ------ `x` is overwritten here before the previous value is read
30+
31+
warning: value assigned to `x` is never read
32+
--> $DIR/unused-assignments-diverging-branch-issue-156416.rs:33:9
33+
|
34+
LL | x = 35;
35+
| ^^^^^^ this value is reassigned later and never used
36+
...
37+
LL | x = 99;
38+
| ------ `x` is overwritten here before the previous value is read
39+
40+
warning: 4 warnings emitted
41+

0 commit comments

Comments
 (0)