Skip to content

Commit 95402c7

Browse files
Do not project to uninhabited variant in JumpThreading, const printing
1 parent 5bd5d21 commit 95402c7

5 files changed

+339
-1
lines changed

compiler/rustc_const_eval/src/const_eval/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
8989
}
9090
ty::Adt(def, _) => {
9191
let variant = ecx.read_discriminant(&op).ok()?;
92+
if op.layout.for_variant(&ecx, variant).abi.is_uninhabited() {
93+
return None;
94+
}
9295
let down = ecx.project_downcast(&op, variant).ok()?;
9396
(def.variants()[variant].fields.len(), Some(variant), down)
9497
}

compiler/rustc_mir_transform/src/jump_threading.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,12 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
370370
constant,
371371
&mut |elem, op| match elem {
372372
TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).ok(),
373-
TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).ok(),
373+
TrackElem::Variant(idx) => {
374+
if op.layout.for_variant(&self.ecx, idx).abi.is_uninhabited() {
375+
return None;
376+
}
377+
self.ecx.project_downcast(op, idx).ok()
378+
}
374379
TrackElem::Discriminant => {
375380
let variant = self.ecx.read_discriminant(op).ok()?;
376381
let discr_value =
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// unit-test: JumpThreading
2+
// compile-flags: -Zmir-opt-level=3 -Zunsound-mir-opts
3+
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
4+
// skip-filecheck
5+
6+
pub enum HiddenType {}
7+
8+
pub struct Wrap<T>(T);
9+
10+
// EMIT_MIR jump_threading_uninhabited.test_questionmark.JumpThreading.diff
11+
fn test_questionmark() -> Result<(), ()> {
12+
Ok(Ok(()))??;
13+
Ok(())
14+
}
15+
16+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
- // MIR for `test_questionmark` before JumpThreading
2+
+ // MIR for `test_questionmark` after JumpThreading
3+
4+
fn test_questionmark() -> Result<(), ()> {
5+
let mut _0: std::result::Result<(), ()>;
6+
let mut _1: std::ops::ControlFlow<std::result::Result<std::convert::Infallible, ()>>;
7+
let mut _2: std::result::Result<(), ()>;
8+
let mut _3: std::ops::ControlFlow<std::result::Result<std::convert::Infallible, ()>, std::result::Result<(), ()>>;
9+
let mut _4: std::result::Result<std::result::Result<(), ()>, ()>;
10+
let mut _5: isize;
11+
let _6: std::result::Result<(), ()>;
12+
let mut _7: isize;
13+
scope 1 {
14+
debug residual => const Result::<Infallible, ()>::Err(());
15+
scope 2 {
16+
scope 15 (inlined #[track_caller] <Result<(), ()> as FromResidual<Result<Infallible, ()>>>::from_residual) {
17+
debug residual => const Result::<Infallible, ()>::Err(());
18+
scope 16 {
19+
debug e => const ();
20+
scope 17 (inlined <() as From<()>>::from) {
21+
debug t => const ();
22+
}
23+
}
24+
}
25+
}
26+
}
27+
scope 3 {
28+
debug val => const Result::<(), ()>::Ok(());
29+
scope 4 {
30+
}
31+
}
32+
scope 5 {
33+
debug residual => const Result::<Infallible, ()>::Err(());
34+
scope 6 {
35+
scope 18 (inlined #[track_caller] <Result<(), ()> as FromResidual<Result<Infallible, ()>>>::from_residual) {
36+
debug residual => const Result::<Infallible, ()>::Err(());
37+
scope 19 {
38+
debug e => const ();
39+
scope 20 (inlined <() as From<()>>::from) {
40+
debug t => const ();
41+
}
42+
}
43+
}
44+
}
45+
}
46+
scope 7 {
47+
debug val => const ();
48+
scope 8 {
49+
}
50+
}
51+
scope 9 (inlined <Result<Result<(), ()>, ()> as Try>::branch) {
52+
debug self => const Result::<Result<(), ()>, ()>::Ok(Result::<(), ()>::Ok(()));
53+
let _8: std::result::Result<(), ()>;
54+
scope 10 {
55+
debug v => const Result::<(), ()>::Ok(());
56+
}
57+
scope 11 {
58+
debug e => const ();
59+
}
60+
}
61+
scope 12 (inlined <Result<(), ()> as Try>::branch) {
62+
debug self => const Result::<(), ()>::Ok(());
63+
let mut _9: isize;
64+
scope 13 {
65+
debug v => const ();
66+
}
67+
scope 14 {
68+
debug e => const ();
69+
}
70+
}
71+
72+
bb0: {
73+
StorageLive(_1);
74+
StorageLive(_2);
75+
StorageLive(_3);
76+
StorageLive(_4);
77+
_4 = const Result::<Result<(), ()>, ()>::Ok(Result::<(), ()>::Ok(()));
78+
StorageLive(_8);
79+
goto -> bb8;
80+
}
81+
82+
bb1: {
83+
_6 = const Result::<(), ()>::Ok(());
84+
_2 = const Result::<(), ()>::Ok(());
85+
StorageLive(_9);
86+
_9 = const 0_isize;
87+
goto -> bb10;
88+
}
89+
90+
bb2: {
91+
_0 = const Result::<(), ()>::Err(());
92+
StorageDead(_2);
93+
goto -> bb5;
94+
}
95+
96+
bb3: {
97+
StorageDead(_3);
98+
StorageDead(_1);
99+
_0 = const Result::<(), ()>::Ok(());
100+
goto -> bb6;
101+
}
102+
103+
bb4: {
104+
_0 = const Result::<(), ()>::Err(());
105+
goto -> bb5;
106+
}
107+
108+
bb5: {
109+
StorageDead(_3);
110+
StorageDead(_1);
111+
goto -> bb6;
112+
}
113+
114+
bb6: {
115+
return;
116+
}
117+
118+
bb7: {
119+
_3 = const ControlFlow::<Result<Infallible, ()>, Result<(), ()>>::Break(Result::<Infallible, ()>::Err(()));
120+
StorageDead(_8);
121+
StorageDead(_4);
122+
_5 = discriminant(_3);
123+
- switchInt(move _5) -> [0: bb1, 1: bb2, otherwise: bb11];
124+
+ goto -> bb2;
125+
}
126+
127+
bb8: {
128+
_8 = const Result::<(), ()>::Ok(());
129+
_3 = const ControlFlow::<Result<Infallible, ()>, Result<(), ()>>::Continue(Result::<(), ()>::Ok(()));
130+
StorageDead(_8);
131+
StorageDead(_4);
132+
_5 = const 0_isize;
133+
goto -> bb1;
134+
}
135+
136+
bb9: {
137+
_1 = const ControlFlow::<Result<Infallible, ()>>::Break(Result::<Infallible, ()>::Err(()));
138+
StorageDead(_9);
139+
StorageDead(_2);
140+
_7 = discriminant(_1);
141+
- switchInt(move _7) -> [0: bb3, 1: bb4, otherwise: bb11];
142+
+ goto -> bb4;
143+
}
144+
145+
bb10: {
146+
_1 = const ControlFlow::<Result<Infallible, ()>>::Continue(());
147+
StorageDead(_9);
148+
StorageDead(_2);
149+
_7 = const 0_isize;
150+
goto -> bb3;
151+
}
152+
153+
bb11: {
154+
unreachable;
155+
}
156+
}
157+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
- // MIR for `test_questionmark` before JumpThreading
2+
+ // MIR for `test_questionmark` after JumpThreading
3+
4+
fn test_questionmark() -> Result<(), ()> {
5+
let mut _0: std::result::Result<(), ()>;
6+
let mut _1: std::ops::ControlFlow<std::result::Result<std::convert::Infallible, ()>>;
7+
let mut _2: std::result::Result<(), ()>;
8+
let mut _3: std::ops::ControlFlow<std::result::Result<std::convert::Infallible, ()>, std::result::Result<(), ()>>;
9+
let mut _4: std::result::Result<std::result::Result<(), ()>, ()>;
10+
let mut _5: isize;
11+
let _6: std::result::Result<(), ()>;
12+
let mut _7: isize;
13+
scope 1 {
14+
debug residual => const Result::<Infallible, ()>::Err(());
15+
scope 2 {
16+
scope 15 (inlined #[track_caller] <Result<(), ()> as FromResidual<Result<Infallible, ()>>>::from_residual) {
17+
debug residual => const Result::<Infallible, ()>::Err(());
18+
scope 16 {
19+
debug e => const ();
20+
scope 17 (inlined <() as From<()>>::from) {
21+
debug t => const ();
22+
}
23+
}
24+
}
25+
}
26+
}
27+
scope 3 {
28+
debug val => const Result::<(), ()>::Ok(());
29+
scope 4 {
30+
}
31+
}
32+
scope 5 {
33+
debug residual => const Result::<Infallible, ()>::Err(());
34+
scope 6 {
35+
scope 18 (inlined #[track_caller] <Result<(), ()> as FromResidual<Result<Infallible, ()>>>::from_residual) {
36+
debug residual => const Result::<Infallible, ()>::Err(());
37+
scope 19 {
38+
debug e => const ();
39+
scope 20 (inlined <() as From<()>>::from) {
40+
debug t => const ();
41+
}
42+
}
43+
}
44+
}
45+
}
46+
scope 7 {
47+
debug val => const ();
48+
scope 8 {
49+
}
50+
}
51+
scope 9 (inlined <Result<Result<(), ()>, ()> as Try>::branch) {
52+
debug self => const Result::<Result<(), ()>, ()>::Ok(Result::<(), ()>::Ok(()));
53+
let _8: std::result::Result<(), ()>;
54+
scope 10 {
55+
debug v => const Result::<(), ()>::Ok(());
56+
}
57+
scope 11 {
58+
debug e => const ();
59+
}
60+
}
61+
scope 12 (inlined <Result<(), ()> as Try>::branch) {
62+
debug self => const Result::<(), ()>::Ok(());
63+
let mut _9: isize;
64+
scope 13 {
65+
debug v => const ();
66+
}
67+
scope 14 {
68+
debug e => const ();
69+
}
70+
}
71+
72+
bb0: {
73+
StorageLive(_1);
74+
StorageLive(_2);
75+
StorageLive(_3);
76+
StorageLive(_4);
77+
_4 = const Result::<Result<(), ()>, ()>::Ok(Result::<(), ()>::Ok(()));
78+
StorageLive(_8);
79+
goto -> bb8;
80+
}
81+
82+
bb1: {
83+
_6 = const Result::<(), ()>::Ok(());
84+
_2 = const Result::<(), ()>::Ok(());
85+
StorageLive(_9);
86+
_9 = const 0_isize;
87+
goto -> bb10;
88+
}
89+
90+
bb2: {
91+
_0 = const Result::<(), ()>::Err(());
92+
StorageDead(_2);
93+
goto -> bb5;
94+
}
95+
96+
bb3: {
97+
StorageDead(_3);
98+
StorageDead(_1);
99+
_0 = const Result::<(), ()>::Ok(());
100+
goto -> bb6;
101+
}
102+
103+
bb4: {
104+
_0 = const Result::<(), ()>::Err(());
105+
goto -> bb5;
106+
}
107+
108+
bb5: {
109+
StorageDead(_3);
110+
StorageDead(_1);
111+
goto -> bb6;
112+
}
113+
114+
bb6: {
115+
return;
116+
}
117+
118+
bb7: {
119+
_3 = const ControlFlow::<Result<Infallible, ()>, Result<(), ()>>::Break(Result::<Infallible, ()>::Err(()));
120+
StorageDead(_8);
121+
StorageDead(_4);
122+
_5 = discriminant(_3);
123+
- switchInt(move _5) -> [0: bb1, 1: bb2, otherwise: bb11];
124+
+ goto -> bb2;
125+
}
126+
127+
bb8: {
128+
_8 = const Result::<(), ()>::Ok(());
129+
_3 = const ControlFlow::<Result<Infallible, ()>, Result<(), ()>>::Continue(Result::<(), ()>::Ok(()));
130+
StorageDead(_8);
131+
StorageDead(_4);
132+
_5 = const 0_isize;
133+
goto -> bb1;
134+
}
135+
136+
bb9: {
137+
_1 = const ControlFlow::<Result<Infallible, ()>>::Break(Result::<Infallible, ()>::Err(()));
138+
StorageDead(_9);
139+
StorageDead(_2);
140+
_7 = discriminant(_1);
141+
- switchInt(move _7) -> [0: bb3, 1: bb4, otherwise: bb11];
142+
+ goto -> bb4;
143+
}
144+
145+
bb10: {
146+
_1 = const ControlFlow::<Result<Infallible, ()>>::Continue(());
147+
StorageDead(_9);
148+
StorageDead(_2);
149+
_7 = const 0_isize;
150+
goto -> bb3;
151+
}
152+
153+
bb11: {
154+
unreachable;
155+
}
156+
}
157+

0 commit comments

Comments
 (0)