Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 34f2672

Browse files
committed
Update MIR with MirPatch in UninhabitedEnumBranching
1 parent b61a326 commit 34f2672

9 files changed

+115
-112
lines changed

compiler/rustc_middle/src/mir/patch.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ pub struct MirPatch<'tcx> {
1111
resume_block: Option<BasicBlock>,
1212
// Only for unreachable in cleanup path.
1313
unreachable_cleanup_block: Option<BasicBlock>,
14+
// Only for unreachable not in cleanup path.
15+
unreachable_no_cleanup_block: Option<BasicBlock>,
1416
// Cached block for UnwindTerminate (with reason)
1517
terminate_block: Option<(BasicBlock, UnwindTerminateReason)>,
1618
body_span: Span,
@@ -27,6 +29,7 @@ impl<'tcx> MirPatch<'tcx> {
2729
next_local: body.local_decls.len(),
2830
resume_block: None,
2931
unreachable_cleanup_block: None,
32+
unreachable_no_cleanup_block: None,
3033
terminate_block: None,
3134
body_span: body.span,
3235
};
@@ -43,9 +46,12 @@ impl<'tcx> MirPatch<'tcx> {
4346
// Check if we already have an unreachable block
4447
if matches!(block.terminator().kind, TerminatorKind::Unreachable)
4548
&& block.statements.is_empty()
46-
&& block.is_cleanup
4749
{
48-
result.unreachable_cleanup_block = Some(bb);
50+
if block.is_cleanup {
51+
result.unreachable_cleanup_block = Some(bb);
52+
} else {
53+
result.unreachable_no_cleanup_block = Some(bb);
54+
}
4955
continue;
5056
}
5157

@@ -95,6 +101,23 @@ impl<'tcx> MirPatch<'tcx> {
95101
bb
96102
}
97103

104+
pub fn unreachable_no_cleanup_block(&mut self) -> BasicBlock {
105+
if let Some(bb) = self.unreachable_no_cleanup_block {
106+
return bb;
107+
}
108+
109+
let bb = self.new_block(BasicBlockData {
110+
statements: vec![],
111+
terminator: Some(Terminator {
112+
source_info: SourceInfo::outermost(self.body_span),
113+
kind: TerminatorKind::Unreachable,
114+
}),
115+
is_cleanup: false,
116+
});
117+
self.unreachable_no_cleanup_block = Some(bb);
118+
bb
119+
}
120+
98121
pub fn terminate_block(&mut self, reason: UnwindTerminateReason) -> BasicBlock {
99122
if let Some((cached_bb, cached_reason)) = self.terminate_block
100123
&& reason == cached_reason

compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs

Lines changed: 30 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
33
use crate::MirPass;
44
use rustc_data_structures::fx::FxHashSet;
5+
use rustc_middle::mir::patch::MirPatch;
56
use rustc_middle::mir::{
6-
BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, Terminator, TerminatorKind,
7+
BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, TerminatorKind,
78
};
89
use rustc_middle::ty::layout::TyAndLayout;
910
use rustc_middle::ty::{Ty, TyCtxt};
@@ -77,8 +78,8 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
7778
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
7879
trace!("UninhabitedEnumBranching starting for {:?}", body.source);
7980

80-
let mut removable_switchs = Vec::new();
81-
let mut otherwise_is_last_variant_switchs = Vec::new();
81+
let mut unreachable_targets = Vec::new();
82+
let mut patch = MirPatch::new(body);
8283

8384
for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
8485
trace!("processing block {:?}", bb);
@@ -107,49 +108,41 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
107108

108109
trace!("allowed_variants = {:?}", allowed_variants);
109110

110-
let terminator = bb_data.terminator();
111-
let TerminatorKind::SwitchInt { targets, .. } = &terminator.kind else { bug!() };
111+
unreachable_targets.clear();
112+
let TerminatorKind::SwitchInt { targets, discr } = &bb_data.terminator().kind else {
113+
bug!()
114+
};
112115

113116
for (index, (val, _)) in targets.iter().enumerate() {
114117
if !allowed_variants.remove(&val) {
115-
removable_switchs.push((bb, index));
118+
unreachable_targets.push(index);
116119
}
117120
}
118121

119-
if allowed_variants.is_empty() {
120-
removable_switchs.push((bb, targets.iter().count()));
121-
} else if allowed_variants.len() == 1
122-
&& !body.basic_blocks[targets.otherwise()].is_empty_unreachable()
123-
{
124-
#[allow(rustc::potential_query_instability)]
125-
let last_variant = *allowed_variants.iter().next().unwrap();
126-
otherwise_is_last_variant_switchs.push((bb, last_variant));
127-
}
128-
}
122+
let replace_otherwise_to_unreachable = allowed_variants.len() <= 1
123+
&& !body.basic_blocks[targets.otherwise()].is_empty_unreachable();
129124

130-
for (bb, last_variant) in otherwise_is_last_variant_switchs {
131-
let bb_data = &mut body.basic_blocks.as_mut()[bb];
132-
let terminator = bb_data.terminator_mut();
133-
let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind else { bug!() };
134-
targets.add_target(last_variant, targets.otherwise());
135-
removable_switchs.push((bb, targets.iter().count()));
136-
}
125+
if unreachable_targets.is_empty() && !replace_otherwise_to_unreachable {
126+
continue;
127+
}
137128

138-
if removable_switchs.is_empty() {
139-
return;
129+
let unreachable_block = patch.unreachable_no_cleanup_block();
130+
let mut targets = targets.clone();
131+
if replace_otherwise_to_unreachable {
132+
let otherwise_is_last_variant = !allowed_variants.is_empty();
133+
if otherwise_is_last_variant {
134+
#[allow(rustc::potential_query_instability)]
135+
let last_variant = *allowed_variants.iter().next().unwrap();
136+
targets.add_target(last_variant, targets.otherwise());
137+
}
138+
unreachable_targets.push(targets.iter().count());
139+
}
140+
for index in unreachable_targets.iter() {
141+
targets.all_targets_mut()[*index] = unreachable_block;
142+
}
143+
patch.patch_terminator(bb, TerminatorKind::SwitchInt { targets, discr: discr.clone() });
140144
}
141145

142-
let new_block = BasicBlockData::new(Some(Terminator {
143-
source_info: body.basic_blocks[removable_switchs[0].0].terminator().source_info,
144-
kind: TerminatorKind::Unreachable,
145-
}));
146-
let unreachable_block = body.basic_blocks.as_mut().push(new_block);
147-
148-
for (bb, index) in removable_switchs {
149-
let bb = &mut body.basic_blocks.as_mut()[bb];
150-
let terminator = bb.terminator_mut();
151-
let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind else { bug!() };
152-
targets.all_targets_mut()[index] = unreachable_block;
153-
}
146+
patch.apply(body);
154147
}
155148
}

tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@
4343
+ _2 = const Option::<Layout>::None;
4444
StorageLive(_10);
4545
- _10 = discriminant(_2);
46-
- switchInt(move _10) -> [0: bb2, 1: bb3, otherwise: bb5];
46+
- switchInt(move _10) -> [0: bb3, 1: bb4, otherwise: bb2];
4747
+ _10 = const 0_isize;
48-
+ switchInt(const 0_isize) -> [0: bb2, 1: bb3, otherwise: bb5];
48+
+ switchInt(const 0_isize) -> [0: bb3, 1: bb4, otherwise: bb2];
4949
}
5050

5151
bb1: {
@@ -68,10 +68,14 @@
6868
}
6969

7070
bb2: {
71-
_11 = option::unwrap_failed() -> unwind continue;
71+
unreachable;
7272
}
7373

7474
bb3: {
75+
_11 = option::unwrap_failed() -> unwind continue;
76+
}
77+
78+
bb4: {
7579
- _1 = move ((_2 as Some).0: std::alloc::Layout);
7680
+ _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }};
7781
StorageDead(_10);
@@ -86,20 +90,16 @@
8690
+ _7 = const {ALLOC1<imm>: &std::alloc::Global};
8791
StorageLive(_8);
8892
- _8 = _1;
89-
- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb4, unwind continue];
93+
- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb5, unwind continue];
9094
+ _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }};
91-
+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb4, unwind continue];
95+
+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb5, unwind continue];
9296
}
9397

94-
bb4: {
98+
bb5: {
9599
StorageDead(_8);
96100
StorageDead(_7);
97101
_5 = Result::<NonNull<[u8]>, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue];
98102
}
99-
100-
bb5: {
101-
unreachable;
102-
}
103103
}
104104
+
105105
+ ALLOC0 (size: 16, align: 8) {

tests/mir-opt/separate_const_switch.identity.JumpThreading.diff

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,21 @@
5252
StorageLive(_9);
5353
StorageLive(_10);
5454
_8 = discriminant(_1);
55-
switchInt(move _8) -> [0: bb5, 1: bb4, otherwise: bb6];
55+
switchInt(move _8) -> [0: bb6, 1: bb5, otherwise: bb1];
5656
}
5757

5858
bb1: {
59+
unreachable;
60+
}
61+
62+
bb2: {
5963
_7 = ((_2 as Continue).0: i32);
6064
_0 = Result::<i32, i32>::Ok(_7);
6165
StorageDead(_2);
6266
return;
6367
}
6468

65-
bb2: {
69+
bb3: {
6670
_5 = ((_2 as Break).0: std::result::Result<std::convert::Infallible, i32>);
6771
StorageLive(_6);
6872
_6 = _5;
@@ -73,34 +77,30 @@
7377
return;
7478
}
7579

76-
bb3: {
80+
bb4: {
7781
StorageDead(_10);
7882
StorageDead(_9);
7983
StorageDead(_8);
8084
StorageDead(_3);
8185
_4 = discriminant(_2);
82-
- switchInt(move _4) -> [0: bb1, 1: bb2, otherwise: bb6];
83-
+ goto -> bb1;
86+
- switchInt(move _4) -> [0: bb2, 1: bb3, otherwise: bb1];
87+
+ goto -> bb2;
8488
}
8589

86-
bb4: {
90+
bb5: {
8791
_10 = ((_1 as Err).0: i32);
8892
StorageLive(_11);
8993
_11 = Result::<Infallible, i32>::Err(_10);
9094
_2 = ControlFlow::<Result<Infallible, i32>, i32>::Break(move _11);
9195
StorageDead(_11);
92-
- goto -> bb3;
96+
- goto -> bb4;
9397
+ goto -> bb7;
9498
}
9599

96-
bb5: {
100+
bb6: {
97101
_9 = ((_1 as Ok).0: i32);
98102
_2 = ControlFlow::<Result<Infallible, i32>, i32>::Continue(_9);
99-
goto -> bb3;
100-
}
101-
102-
bb6: {
103-
unreachable;
103+
goto -> bb4;
104104
+ }
105105
+
106106
+ bb7: {
@@ -109,7 +109,7 @@
109109
+ StorageDead(_8);
110110
+ StorageDead(_3);
111111
+ _4 = discriminant(_2);
112-
+ goto -> bb2;
112+
+ goto -> bb3;
113113
}
114114
}
115115

tests/mir-opt/separate_const_switch.too_complex.JumpThreading.diff

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,54 +27,54 @@
2727
bb0: {
2828
StorageLive(_2);
2929
_3 = discriminant(_1);
30-
switchInt(move _3) -> [0: bb2, 1: bb1, otherwise: bb7];
30+
switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1];
3131
}
3232

3333
bb1: {
34+
unreachable;
35+
}
36+
37+
bb2: {
3438
_5 = ((_1 as Err).0: usize);
3539
_2 = ControlFlow::<usize, i32>::Break(_5);
36-
- goto -> bb3;
40+
- goto -> bb4;
3741
+ goto -> bb8;
3842
}
3943

40-
bb2: {
44+
bb3: {
4145
_4 = ((_1 as Ok).0: i32);
4246
_2 = ControlFlow::<usize, i32>::Continue(_4);
43-
goto -> bb3;
47+
goto -> bb4;
4448
}
4549

46-
bb3: {
50+
bb4: {
4751
_6 = discriminant(_2);
48-
- switchInt(move _6) -> [0: bb5, 1: bb4, otherwise: bb7];
49-
+ goto -> bb5;
52+
- switchInt(move _6) -> [0: bb6, 1: bb5, otherwise: bb1];
53+
+ goto -> bb6;
5054
}
5155

52-
bb4: {
56+
bb5: {
5357
StorageLive(_8);
5458
_8 = ((_2 as Break).0: usize);
5559
_0 = const Option::<i32>::None;
5660
StorageDead(_8);
57-
goto -> bb6;
61+
goto -> bb7;
5862
}
5963

60-
bb5: {
64+
bb6: {
6165
_7 = ((_2 as Continue).0: i32);
6266
_0 = Option::<i32>::Some(_7);
63-
goto -> bb6;
67+
goto -> bb7;
6468
}
6569

66-
bb6: {
70+
bb7: {
6771
StorageDead(_2);
6872
return;
69-
}
70-
71-
bb7: {
72-
unreachable;
7373
+ }
7474
+
7575
+ bb8: {
7676
+ _6 = discriminant(_2);
77-
+ goto -> bb4;
77+
+ goto -> bb5;
7878
}
7979
}
8080

tests/mir-opt/uninhabited_enum_branching.byref.UninhabitedEnumBranching.panic-unwind.diff

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
_4 = &(_1.1: Test3);
3232
_5 = discriminant((*_4));
3333
- switchInt(move _5) -> [0: bb3, 1: bb4, 2: bb5, 3: bb2, otherwise: bb1];
34-
+ switchInt(move _5) -> [0: bb12, 1: bb12, 2: bb5, 3: bb2, otherwise: bb12];
34+
+ switchInt(move _5) -> [0: bb1, 1: bb1, 2: bb5, 3: bb2, otherwise: bb1];
3535
}
3636

3737
bb1: {
@@ -73,7 +73,7 @@
7373
StorageLive(_9);
7474
_10 = discriminant((_1.1: Test3));
7575
- switchInt(move _10) -> [0: bb8, 1: bb9, 2: bb10, 3: bb7, otherwise: bb1];
76-
+ switchInt(move _10) -> [0: bb12, 1: bb12, 2: bb10, 3: bb7, otherwise: bb12];
76+
+ switchInt(move _10) -> [0: bb1, 1: bb1, 2: bb10, 3: bb7, otherwise: bb1];
7777
}
7878

7979
bb7: {
@@ -110,10 +110,6 @@
110110
_0 = const ();
111111
StorageDead(_1);
112112
return;
113-
+ }
114-
+
115-
+ bb12: {
116-
+ unreachable;
117113
}
118114
}
119115

0 commit comments

Comments
 (0)