Skip to content

Commit 6bad178

Browse files
Do not remove trivial SwitchInt with mir-opt-level=0
1 parent 19cab6b commit 6bad178

13 files changed

+163
-25
lines changed

Diff for: compiler/rustc_mir_transform/src/early_otherwise_branch.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
224224
// Since this optimization adds new basic blocks and invalidates others,
225225
// clean up the cfg to make it nicer for other passes
226226
if should_cleanup {
227-
simplify_cfg(body);
227+
simplify_cfg(tcx, body);
228228
}
229229
}
230230

Diff for: compiler/rustc_mir_transform/src/inline.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ impl<'tcx> crate::MirPass<'tcx> for Inline {
6363
let _guard = span.enter();
6464
if inline::<NormalInliner<'tcx>>(tcx, body) {
6565
debug!("running simplify cfg on {:?}", body.source);
66-
simplify_cfg(body);
66+
simplify_cfg(tcx, body);
6767
deref_finder(tcx, body);
6868
}
6969
}
@@ -99,7 +99,7 @@ impl<'tcx> crate::MirPass<'tcx> for ForceInline {
9999
let _guard = span.enter();
100100
if inline::<ForceInliner<'tcx>>(tcx, body) {
101101
debug!("running simplify cfg on {:?}", body.source);
102-
simplify_cfg(body);
102+
simplify_cfg(tcx, body);
103103
deref_finder(tcx, body);
104104
}
105105
}

Diff for: compiler/rustc_mir_transform/src/match_branches.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
4545
}
4646

4747
if should_cleanup {
48-
simplify_cfg(body);
48+
simplify_cfg(tcx, body);
4949
}
5050
}
5151

Diff for: compiler/rustc_mir_transform/src/remove_unneeded_drops.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUnneededDrops {
3535
// if we applied optimizations, we potentially have some cfg to cleanup to
3636
// make it easier for further passes
3737
if should_simplify {
38-
simplify_cfg(body);
38+
simplify_cfg(tcx, body);
3939
}
4040
}
4141

Diff for: compiler/rustc_mir_transform/src/simplify.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ impl SimplifyCfg {
6666
}
6767
}
6868

69-
pub(super) fn simplify_cfg(body: &mut Body<'_>) {
70-
CfgSimplifier::new(body).simplify();
69+
pub(super) fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
70+
CfgSimplifier::new(tcx, body).simplify();
7171
remove_dead_blocks(body);
7272

7373
// FIXME: Should probably be moved into some kind of pass manager
@@ -79,9 +79,9 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyCfg {
7979
self.name()
8080
}
8181

82-
fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
82+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
8383
debug!("SimplifyCfg({:?}) - simplifying {:?}", self.name(), body.source);
84-
simplify_cfg(body);
84+
simplify_cfg(tcx, body);
8585
}
8686

8787
fn is_required(&self) -> bool {
@@ -90,12 +90,13 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyCfg {
9090
}
9191

9292
struct CfgSimplifier<'a, 'tcx> {
93+
mir_opt_level: usize,
9394
basic_blocks: &'a mut IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
9495
pred_count: IndexVec<BasicBlock, u32>,
9596
}
9697

9798
impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
98-
fn new(body: &'a mut Body<'tcx>) -> Self {
99+
fn new(tcx: TyCtxt<'tcx>, body: &'a mut Body<'tcx>) -> Self {
99100
let mut pred_count = IndexVec::from_elem(0u32, &body.basic_blocks);
100101

101102
// we can't use mir.predecessors() here because that counts
@@ -112,7 +113,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
112113

113114
let basic_blocks = body.basic_blocks_mut();
114115

115-
CfgSimplifier { basic_blocks, pred_count }
116+
CfgSimplifier { mir_opt_level: tcx.sess.mir_opt_level(), basic_blocks, pred_count }
116117
}
117118

118119
fn simplify(mut self) {
@@ -253,9 +254,14 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
253254

254255
// turn a branch with all successors identical to a goto
255256
fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
256-
match terminator.kind {
257-
TerminatorKind::SwitchInt { .. } => {}
258-
_ => return false,
257+
// Removing a `SwitchInt` terminator may remove reads that result in UB,
258+
// so we must not apply this optimization when mir-opt-level = 0.
259+
if self.mir_opt_level == 0 {
260+
return false;
261+
}
262+
263+
let TerminatorKind::SwitchInt { .. } = terminator.kind else {
264+
return false;
259265
};
260266

261267
let first_succ = {
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use std::mem::MaybeUninit;
2+
3+
fn main() {
4+
let uninit: MaybeUninit<i32> = MaybeUninit::uninit();
5+
let bad_ref: &i32 = unsafe { uninit.assume_init_ref() };
6+
let &(0 | _) = bad_ref;
7+
//~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
8+
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
2+
--> tests/fail/read_from_trivial_switch.rs:LL:CC
3+
|
4+
LL | let &(0 | _) = bad_ref;
5+
| ^^^^^^^^ using uninitialized data, but this operation requires initialized memory
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= note: BACKTRACE:
10+
= note: inside `main` at tests/fail/read_from_trivial_switch.rs:LL:CC
11+
12+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
13+
14+
error: aborting due to 1 previous error
15+

Diff for: tests/mir-opt/early_otherwise_branch_unwind.poll.EarlyOtherwiseBranch.diff

+6-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
let mut _7: bool;
1313
let mut _8: bool;
1414
let mut _9: isize;
15+
let mut _10: isize;
1516
scope 1 {
1617
debug _trailers => _5;
1718
}
@@ -99,12 +100,13 @@
99100
}
100101

101102
bb15: {
102-
goto -> bb14;
103+
_9 = discriminant(((((_1 as Ready).0: std::result::Result<std::option::Option<std::vec::Vec<u8>>, u8>) as Ok).0: std::option::Option<std::vec::Vec<u8>>));
104+
switchInt(move _9) -> [1: bb14, otherwise: bb14];
103105
}
104106

105107
bb16: {
106-
_9 = discriminant(((_1 as Ready).0: std::result::Result<std::option::Option<std::vec::Vec<u8>>, u8>));
107-
switchInt(move _9) -> [0: bb13, otherwise: bb12];
108+
_10 = discriminant(((_1 as Ready).0: std::result::Result<std::option::Option<std::vec::Vec<u8>>, u8>));
109+
switchInt(move _10) -> [0: bb13, otherwise: bb12];
108110
}
109111

110112
bb17: {
@@ -116,7 +118,7 @@
116118
}
117119

118120
bb19 (cleanup): {
119-
goto -> bb9;
121+
switchInt(copy _2) -> [1: bb9, otherwise: bb9];
120122
}
121123

122124
bb20 (cleanup): {

Diff for: tests/mir-opt/early_otherwise_branch_unwind.unwind.EarlyOtherwiseBranch.diff

+6-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
let mut _6: bool;
1212
let mut _7: bool;
1313
let mut _8: isize;
14+
let mut _9: isize;
1415
scope 1 {
1516
debug _v => _5;
1617
}
@@ -92,12 +93,13 @@
9293
}
9394

9495
bb15: {
95-
goto -> bb14;
96+
_8 = discriminant(((((_1 as Some).0: std::option::Option<std::option::Option<T>>) as Some).0: std::option::Option<T>));
97+
switchInt(move _8) -> [1: bb14, otherwise: bb14];
9698
}
9799

98100
bb16: {
99-
_8 = discriminant(((_1 as Some).0: std::option::Option<std::option::Option<T>>));
100-
switchInt(move _8) -> [1: bb13, otherwise: bb12];
101+
_9 = discriminant(((_1 as Some).0: std::option::Option<std::option::Option<T>>));
102+
switchInt(move _9) -> [1: bb13, otherwise: bb12];
101103
}
102104

103105
bb17: {
@@ -109,7 +111,7 @@
109111
}
110112

111113
bb19 (cleanup): {
112-
goto -> bb9;
114+
switchInt(copy _2) -> [1: bb9, otherwise: bb9];
113115
}
114116

115117
bb20 (cleanup): {

Diff for: tests/mir-opt/gvn_copy_aggregate.remove_storage_dead.GVN.diff

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
+ _2 = copy _5;
4040
+ nop;
4141
_7 = discriminant(_3);
42+
switchInt(move _7) -> bb2;
43+
}
44+
45+
bb2: {
4246
- StorageDead(_3);
4347
+ nop;
4448
StorageLive(_6);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
- // MIR for `main` before SimplifyCfg-initial
2+
+ // MIR for `main` after SimplifyCfg-initial
3+
4+
| User Type Annotations
5+
| 0: user_ty: Canonical { value: Ty(std::mem::MaybeUninit<i32>), max_universe: U0, variables: [] }, span: $DIR/read_from_trivial_switch.rs:7:17: 7:33, inferred_ty: std::mem::MaybeUninit<i32>
6+
| 1: user_ty: Canonical { value: TypeOf(DefId(2:2155 ~ core[aaca]::mem::maybe_uninit::{impl#2}::uninit), UserArgs { args: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(2:2152 ~ core[aaca]::mem::maybe_uninit::{impl#2}), self_ty: std::mem::MaybeUninit<^1> }) }), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/read_from_trivial_switch.rs:7:36: 7:55, inferred_ty: fn() -> std::mem::MaybeUninit<i32> {std::mem::MaybeUninit::<i32>::uninit}
7+
| 2: user_ty: Canonical { value: Ty(std::mem::MaybeUninit<i32>), max_universe: U0, variables: [] }, span: $DIR/read_from_trivial_switch.rs:7:17: 7:33, inferred_ty: std::mem::MaybeUninit<i32>
8+
| 3: user_ty: Canonical { value: Ty(&i32), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/read_from_trivial_switch.rs:8:18: 8:22, inferred_ty: &i32
9+
| 4: user_ty: Canonical { value: Ty(&i32), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/read_from_trivial_switch.rs:8:18: 8:22, inferred_ty: &i32
10+
|
11+
fn main() -> () {
12+
let mut _0: ();
13+
let _1: std::mem::MaybeUninit<i32> as UserTypeProjection { base: UserType(0), projs: [] };
14+
let _3: &i32;
15+
let mut _4: &std::mem::MaybeUninit<i32>;
16+
scope 1 {
17+
debug uninit => _1;
18+
let _2: &i32 as UserTypeProjection { base: UserType(3), projs: [] };
19+
scope 2 {
20+
debug bad_ref => _2;
21+
scope 3 {
22+
}
23+
}
24+
}
25+
26+
bb0: {
27+
StorageLive(_1);
28+
- _1 = MaybeUninit::<i32>::uninit() -> [return: bb1, unwind: bb8];
29+
+ _1 = MaybeUninit::<i32>::uninit() -> [return: bb1, unwind: bb4];
30+
}
31+
32+
bb1: {
33+
FakeRead(ForLet(None), _1);
34+
AscribeUserType(_1, o, UserTypeProjection { base: UserType(2), projs: [] });
35+
StorageLive(_2);
36+
StorageLive(_3);
37+
StorageLive(_4);
38+
_4 = &_1;
39+
- _3 = MaybeUninit::<i32>::assume_init_ref(move _4) -> [return: bb2, unwind: bb8];
40+
+ _3 = MaybeUninit::<i32>::assume_init_ref(move _4) -> [return: bb2, unwind: bb4];
41+
}
42+
43+
bb2: {
44+
_2 = &(*_3);
45+
StorageDead(_4);
46+
FakeRead(ForLet(None), _2);
47+
AscribeUserType(_2, o, UserTypeProjection { base: UserType(4), projs: [] });
48+
StorageDead(_3);
49+
PlaceMention(_2);
50+
- switchInt(copy (*_2)) -> [0: bb4, otherwise: bb3];
51+
+ switchInt(copy (*_2)) -> [0: bb3, otherwise: bb3];
52+
}
53+
54+
bb3: {
55+
- goto -> bb7;
56+
- }
57+
-
58+
- bb4: {
59+
- goto -> bb7;
60+
- }
61+
-
62+
- bb5: {
63+
- goto -> bb3;
64+
- }
65+
-
66+
- bb6: {
67+
- FakeRead(ForMatchedPlace(None), _2);
68+
- unreachable;
69+
- }
70+
-
71+
- bb7: {
72+
_0 = const ();
73+
StorageDead(_2);
74+
StorageDead(_1);
75+
return;
76+
}
77+
78+
- bb8 (cleanup): {
79+
+ bb4 (cleanup): {
80+
resume;
81+
}
82+
}
83+

Diff for: tests/mir-opt/read_from_trivial_switch.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ test-mir-pass: SimplifyCfg-initial
2+
3+
use std::mem::MaybeUninit;
4+
5+
// EMIT_MIR read_from_trivial_switch.main.SimplifyCfg-initial.diff
6+
fn main() {
7+
let uninit: MaybeUninit<i32> = MaybeUninit::uninit();
8+
let bad_ref: &i32 = unsafe { uninit.assume_init_ref() };
9+
// CHECK: switchInt
10+
let &(0 | _) = bad_ref;
11+
}

Diff for: tests/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals-before-const-prop.diff

+10-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
- let mut _5: bool;
1111
- let mut _6: isize;
1212
- let mut _7: isize;
13+
+ let mut _5: isize;
1314
scope 1 {
1415
debug x => _3;
1516
}
@@ -33,17 +34,23 @@
3334
_0 = Option::<Box<()>>::Some(move _4);
3435
StorageDead(_4);
3536
StorageDead(_3);
36-
goto -> bb4;
37+
goto -> bb5;
3738
}
3839

3940
bb3: {
4041
_0 = Option::<Box<()>>::None;
41-
goto -> bb4;
42+
goto -> bb5;
4243
}
4344

4445
bb4: {
45-
- _6 = discriminant(_1);
4646
return;
4747
}
48+
49+
bb5: {
50+
- _6 = discriminant(_1);
51+
- switchInt(move _6) -> [1: bb4, otherwise: bb4];
52+
+ _5 = discriminant(_1);
53+
+ switchInt(move _5) -> [1: bb4, otherwise: bb4];
54+
}
4855
}
4956

0 commit comments

Comments
 (0)