@@ -95,7 +95,7 @@ pub struct EarlyOtherwiseBranch;
95
95
96
96
impl < ' tcx > MirPass < ' tcx > for EarlyOtherwiseBranch {
97
97
fn is_enabled ( & self , sess : & rustc_session:: Session ) -> bool {
98
- sess. mir_opt_level ( ) >= 2
98
+ sess. mir_opt_level ( ) >= 3 && sess . opts . debugging_opts . unsound_mir_opts
99
99
}
100
100
101
101
fn run_pass ( & self , tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
@@ -226,6 +226,37 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
226
226
227
227
/// Returns true if computing the discriminant of `place` may be hoisted out of the branch
228
228
fn may_hoist < ' tcx > ( tcx : TyCtxt < ' tcx > , body : & Body < ' tcx > , place : Place < ' tcx > ) -> bool {
229
+ // FIXME(JakobDegen): This is unsound. Someone could write code like this:
230
+ // ```rust
231
+ // let Q = val;
232
+ // if discriminant(P) == otherwise {
233
+ // let ptr = &mut Q as *mut _ as *mut u8;
234
+ // unsafe { *ptr = 10; } // Any invalid value for the type
235
+ // }
236
+ //
237
+ // match P {
238
+ // A => match Q {
239
+ // A => {
240
+ // // code
241
+ // }
242
+ // _ => {
243
+ // // don't use Q
244
+ // }
245
+ // }
246
+ // _ => {
247
+ // // don't use Q
248
+ // }
249
+ // };
250
+ // ```
251
+ //
252
+ // Hoisting the `discriminant(Q)` out of the `A` arm causes us to compute the discriminant of an
253
+ // invalid value, which is UB.
254
+ //
255
+ // In order to fix this, we would either need to show that the discriminant computation of
256
+ // `place` is computed in all branches, including the `otherwise` branch, or we would need
257
+ // another analysis pass to determine that the place is fully initialized. It might even be best
258
+ // to have the hoisting be performed in a different pass and just do the CFG changing in this
259
+ // pass.
229
260
for ( place, proj) in place. iter_projections ( ) {
230
261
match proj {
231
262
// Dereferencing in the computation of `place` might cause issues from one of two
0 commit comments