Skip to content

Commit 02e12b1

Browse files
borspoliorcetics
authored andcommitted
Auto merge of rust-lang#131244 - clubby789:match-branches-unreachable, r=DianQK
Consider empty-unreachable otherwise branches in MatchBranchSimplification Fixes rust-lang#131219
2 parents 042b5dd + fca8daa commit 02e12b1

7 files changed

+108
-29
lines changed

Diff for: compiler/rustc_data_structures/src/packed.rs

+7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ impl Pu128 {
1818
}
1919
}
2020

21+
impl From<Pu128> for u128 {
22+
#[inline]
23+
fn from(value: Pu128) -> Self {
24+
value.get()
25+
}
26+
}
27+
2128
impl From<u128> for Pu128 {
2229
#[inline]
2330
fn from(value: u128) -> Self {

Diff for: compiler/rustc_middle/src/mir/terminator.rs

+11
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,17 @@ impl SwitchTargets {
6767
&mut self.targets
6868
}
6969

70+
/// Returns a slice with all considered values (not including the fallback).
71+
#[inline]
72+
pub fn all_values(&self) -> &[Pu128] {
73+
&self.values
74+
}
75+
76+
#[inline]
77+
pub fn all_values_mut(&mut self) -> &mut [Pu128] {
78+
&mut self.values
79+
}
80+
7081
/// Finds the `BasicBlock` to which this `SwitchInt` will branch given the
7182
/// specific value. This cannot fail, as it'll return the `otherwise`
7283
/// branch if there's not a specific match for the value.

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

+21-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_middle::mir::*;
77
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
88
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
99
use rustc_type_ir::TyKind::*;
10+
use tracing::instrument;
1011

1112
use super::simplify::simplify_cfg;
1213

@@ -51,7 +52,7 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
5152
}
5253

5354
trait SimplifyMatch<'tcx> {
54-
/// Simplifies a match statement, returning true if the simplification succeeds, false
55+
/// Simplifies a match statement, returning `Some` if the simplification succeeds, `None`
5556
/// otherwise. Generic code is written here, and we generally don't need a custom
5657
/// implementation.
5758
fn simplify(
@@ -159,6 +160,7 @@ struct SimplifyToIf;
159160
/// }
160161
/// ```
161162
impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
163+
#[instrument(level = "debug", skip(self, tcx), ret)]
162164
fn can_simplify(
163165
&mut self,
164166
tcx: TyCtxt<'tcx>,
@@ -167,12 +169,15 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
167169
bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
168170
_discr_ty: Ty<'tcx>,
169171
) -> Option<()> {
170-
if targets.iter().len() != 1 {
171-
return None;
172-
}
172+
let (first, second) = match targets.all_targets() {
173+
&[first, otherwise] => (first, otherwise),
174+
&[first, second, otherwise] if bbs[otherwise].is_empty_unreachable() => (first, second),
175+
_ => {
176+
return None;
177+
}
178+
};
179+
173180
// We require that the possible target blocks all be distinct.
174-
let (_, first) = targets.iter().next().unwrap();
175-
let second = targets.otherwise();
176181
if first == second {
177182
return None;
178183
}
@@ -221,8 +226,14 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
221226
discr_local: Local,
222227
discr_ty: Ty<'tcx>,
223228
) {
224-
let (val, first) = targets.iter().next().unwrap();
225-
let second = targets.otherwise();
229+
let ((val, first), second) = match (targets.all_targets(), targets.all_values()) {
230+
(&[first, otherwise], &[val]) => ((val, first), otherwise),
231+
(&[first, second, otherwise], &[val, _]) if bbs[otherwise].is_empty_unreachable() => {
232+
((val, first), second)
233+
}
234+
_ => unreachable!(),
235+
};
236+
226237
// We already checked that first and second are different blocks,
227238
// and bb_idx has a different terminator from both of them.
228239
let first = &bbs[first];
@@ -297,7 +308,7 @@ struct SimplifyToExp {
297308
transform_kinds: Vec<TransformKind>,
298309
}
299310

300-
#[derive(Clone, Copy)]
311+
#[derive(Clone, Copy, Debug)]
301312
enum ExpectedTransformKind<'a, 'tcx> {
302313
/// Identical statements.
303314
Same(&'a StatementKind<'tcx>),
@@ -362,6 +373,7 @@ impl From<ExpectedTransformKind<'_, '_>> for TransformKind {
362373
/// }
363374
/// ```
364375
impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
376+
#[instrument(level = "debug", skip(self, tcx), ret)]
365377
fn can_simplify(
366378
&mut self,
367379
tcx: TyCtxt<'tcx>,

Diff for: tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-abort.mir

+9-10
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,20 @@ fn num_to_digit(_1: char) -> u32 {
2525
bb1: {
2626
StorageLive(_3);
2727
_3 = discriminant(_2);
28-
switchInt(move _3) -> [1: bb2, 0: bb6, otherwise: bb8];
28+
StorageDead(_2);
29+
switchInt(move _3) -> [1: bb2, otherwise: bb7];
2930
}
3031

3132
bb2: {
3233
StorageDead(_3);
33-
StorageDead(_2);
3434
StorageLive(_4);
3535
_4 = char::methods::<impl char>::to_digit(move _1, const 8_u32) -> [return: bb3, unwind unreachable];
3636
}
3737

3838
bb3: {
3939
StorageLive(_5);
4040
_5 = discriminant(_4);
41-
switchInt(move _5) -> [0: bb4, 1: bb5, otherwise: bb8];
41+
switchInt(move _5) -> [0: bb4, 1: bb5, otherwise: bb6];
4242
}
4343

4444
bb4: {
@@ -49,21 +49,20 @@ fn num_to_digit(_1: char) -> u32 {
4949
_0 = move ((_4 as Some).0: u32);
5050
StorageDead(_5);
5151
StorageDead(_4);
52-
goto -> bb7;
52+
goto -> bb8;
5353
}
5454

5555
bb6: {
56-
StorageDead(_3);
57-
StorageDead(_2);
58-
_0 = const 0_u32;
59-
goto -> bb7;
56+
unreachable;
6057
}
6158

6259
bb7: {
63-
return;
60+
StorageDead(_3);
61+
_0 = const 0_u32;
62+
goto -> bb8;
6463
}
6564

6665
bb8: {
67-
unreachable;
66+
return;
6867
}
6968
}

Diff for: tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir

+9-10
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,20 @@ fn num_to_digit(_1: char) -> u32 {
2525
bb1: {
2626
StorageLive(_3);
2727
_3 = discriminant(_2);
28-
switchInt(move _3) -> [1: bb2, 0: bb6, otherwise: bb8];
28+
StorageDead(_2);
29+
switchInt(move _3) -> [1: bb2, otherwise: bb7];
2930
}
3031

3132
bb2: {
3233
StorageDead(_3);
33-
StorageDead(_2);
3434
StorageLive(_4);
3535
_4 = char::methods::<impl char>::to_digit(move _1, const 8_u32) -> [return: bb3, unwind continue];
3636
}
3737

3838
bb3: {
3939
StorageLive(_5);
4040
_5 = discriminant(_4);
41-
switchInt(move _5) -> [0: bb4, 1: bb5, otherwise: bb8];
41+
switchInt(move _5) -> [0: bb4, 1: bb5, otherwise: bb6];
4242
}
4343

4444
bb4: {
@@ -49,21 +49,20 @@ fn num_to_digit(_1: char) -> u32 {
4949
_0 = move ((_4 as Some).0: u32);
5050
StorageDead(_5);
5151
StorageDead(_4);
52-
goto -> bb7;
52+
goto -> bb8;
5353
}
5454

5555
bb6: {
56-
StorageDead(_3);
57-
StorageDead(_2);
58-
_0 = const 0_u32;
59-
goto -> bb7;
56+
unreachable;
6057
}
6158

6259
bb7: {
63-
return;
60+
StorageDead(_3);
61+
_0 = const 0_u32;
62+
goto -> bb8;
6463
}
6564

6665
bb8: {
67-
unreachable;
66+
return;
6867
}
6968
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
- // MIR for `my_is_some` before MatchBranchSimplification
2+
+ // MIR for `my_is_some` after MatchBranchSimplification
3+
4+
fn my_is_some(_1: Option<()>) -> bool {
5+
debug bar => _1;
6+
let mut _0: bool;
7+
let mut _2: isize;
8+
+ let mut _3: isize;
9+
10+
bb0: {
11+
_2 = discriminant(_1);
12+
- switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1];
13+
- }
14+
-
15+
- bb1: {
16+
- unreachable;
17+
- }
18+
-
19+
- bb2: {
20+
- _0 = const false;
21+
- goto -> bb4;
22+
- }
23+
-
24+
- bb3: {
25+
- _0 = const true;
26+
- goto -> bb4;
27+
- }
28+
-
29+
- bb4: {
30+
+ StorageLive(_3);
31+
+ _3 = move _2;
32+
+ _0 = Ne(copy _3, const 0_isize);
33+
+ StorageDead(_3);
34+
return;
35+
}
36+
}
37+

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

+14
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@ fn foo(bar: Option<()>) {
1919
}
2020
}
2121

22+
// EMIT_MIR matches_reduce_branches.my_is_some.MatchBranchSimplification.diff
23+
// Test for #131219.
24+
fn my_is_some(bar: Option<()>) -> bool {
25+
// CHECK-LABEL: fn my_is_some(
26+
// CHECK: = Ne
27+
// CHECK: return
28+
match bar {
29+
Some(_) => true,
30+
None => false,
31+
}
32+
}
33+
2234
// EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff
2335
fn bar(i: i32) -> (bool, bool, bool, bool) {
2436
// CHECK-LABEL: fn bar(
@@ -651,4 +663,6 @@ fn main() {
651663
let _: u8 = match_trunc_u16_u8_failed(EnumAu16::u0_0x0000);
652664

653665
let _ = match_i128_u128(EnumAi128::A);
666+
667+
let _ = my_is_some(None);
654668
}

0 commit comments

Comments
 (0)