diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs new file mode 100644 index 0000000000000..79aac16355061 --- /dev/null +++ b/compiler/rustc_mir_transform/src/deref_separator.rs @@ -0,0 +1,72 @@ +use crate::MirPass; +use rustc_middle::mir::patch::MirPatch; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +pub struct Derefer; + +pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let mut patch = MirPatch::new(body); + let (basic_blocks, local_decl) = body.basic_blocks_and_local_decls_mut(); + for (block, data) in basic_blocks.iter_enumerated_mut() { + for (i, stmt) in data.statements.iter_mut().enumerate() { + match stmt.kind { + StatementKind::Assign(box (og_place, Rvalue::Ref(region, borrow_knd, place))) => { + for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() { + if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() { + // The type that we are derefing. + let ty = p_ref.ty(local_decl, tcx).ty; + let temp = patch.new_temp(ty, stmt.source_info.span); + + // Because we are assigning this right before original statement + // we are using index i of statement. + let loc = Location { block: block, statement_index: i }; + patch.add_statement(loc, StatementKind::StorageLive(temp)); + + // We are adding current p_ref's projections to our + // temp value. + let deref_place = + Place::from(p_ref.local).project_deeper(p_ref.projection, tcx); + patch.add_assign( + loc, + Place::from(temp), + Rvalue::Use(Operand::Move(deref_place)), + ); + + // We are creating a place by using our temp value's location + // and copying derefed values which we need to create new statement. + let temp_place = + Place::from(temp).project_deeper(&place.projection[idx..], tcx); + let new_stmt = Statement { + source_info: stmt.source_info, + kind: StatementKind::Assign(Box::new(( + og_place, + Rvalue::Ref(region, borrow_knd, temp_place), + ))), + }; + + // Replace current statement with newly created one. + *stmt = new_stmt; + + // Since our job with the temp is done it should be gone + let loc = Location { block: block, statement_index: i + 1 }; + patch.add_statement(loc, StatementKind::StorageDead(temp)); + + // As all projections are off the base projection, if there are + // multiple derefs in the middle of projection, it might cause + // unsoundness, to not let that happen we break the loop. + break; + } + } + } + _ => (), + } + } + } + patch.apply(body); +} + +impl<'tcx> MirPass<'tcx> for Derefer { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + deref_finder(tcx, body); + } +} diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 2fca498a12502..059ee09dfd794 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -53,6 +53,7 @@ mod const_prop_lint; mod coverage; mod deaggregator; mod deduplicate_blocks; +mod deref_separator; mod dest_prop; pub mod dump_mir; mod early_otherwise_branch; @@ -431,6 +432,7 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc // `Deaggregator` is conceptually part of MIR building, some backends rely on it happening // and it can help optimizations. &deaggregator::Deaggregator, + &deref_separator::Derefer, &Lint(const_prop_lint::ConstProp), ]; diff --git a/src/test/mir-opt/derefer_test.main.Derefer.diff b/src/test/mir-opt/derefer_test.main.Derefer.diff new file mode 100644 index 0000000000000..e9a45656ebf8d --- /dev/null +++ b/src/test/mir-opt/derefer_test.main.Derefer.diff @@ -0,0 +1,60 @@ +- // MIR for `main` before Derefer ++ // MIR for `main` after Derefer + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/derefer_test.rs:2:11: 2:11 + let mut _1: (i32, i32); // in scope 0 at $DIR/derefer_test.rs:3:9: 3:14 + let mut _3: &mut (i32, i32); // in scope 0 at $DIR/derefer_test.rs:4:22: 4:28 ++ let mut _6: &mut (i32, i32); // in scope 0 at $DIR/derefer_test.rs:5:13: 5:26 ++ let mut _7: &mut (i32, i32); // in scope 0 at $DIR/derefer_test.rs:6:13: 6:26 + scope 1 { + debug a => _1; // in scope 1 at $DIR/derefer_test.rs:3:9: 3:14 + let mut _2: (i32, &mut (i32, i32)); // in scope 1 at $DIR/derefer_test.rs:4:9: 4:14 + scope 2 { + debug b => _2; // in scope 2 at $DIR/derefer_test.rs:4:9: 4:14 + let _4: &mut i32; // in scope 2 at $DIR/derefer_test.rs:5:9: 5:10 + scope 3 { + debug x => _4; // in scope 3 at $DIR/derefer_test.rs:5:9: 5:10 + let _5: &mut i32; // in scope 3 at $DIR/derefer_test.rs:6:9: 6:10 + scope 4 { + debug y => _5; // in scope 4 at $DIR/derefer_test.rs:6:9: 6:10 + } + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/derefer_test.rs:3:9: 3:14 + (_1.0: i32) = const 42_i32; // scope 0 at $DIR/derefer_test.rs:3:17: 3:24 + (_1.1: i32) = const 43_i32; // scope 0 at $DIR/derefer_test.rs:3:17: 3:24 + StorageLive(_2); // scope 1 at $DIR/derefer_test.rs:4:9: 4:14 + StorageLive(_3); // scope 1 at $DIR/derefer_test.rs:4:22: 4:28 + _3 = &mut _1; // scope 1 at $DIR/derefer_test.rs:4:22: 4:28 + (_2.0: i32) = const 99_i32; // scope 1 at $DIR/derefer_test.rs:4:17: 4:29 + (_2.1: &mut (i32, i32)) = move _3; // scope 1 at $DIR/derefer_test.rs:4:17: 4:29 + StorageDead(_3); // scope 1 at $DIR/derefer_test.rs:4:28: 4:29 + StorageLive(_4); // scope 2 at $DIR/derefer_test.rs:5:9: 5:10 +- _4 = &mut ((*(_2.1: &mut (i32, i32))).0: i32); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 ++ StorageLive(_6); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 ++ _6 = move (_2.1: &mut (i32, i32)); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 ++ _4 = &mut ((*_6).0: i32); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 ++ StorageDead(_6); // scope 3 at $DIR/derefer_test.rs:6:9: 6:10 + StorageLive(_5); // scope 3 at $DIR/derefer_test.rs:6:9: 6:10 +- _5 = &mut ((*(_2.1: &mut (i32, i32))).1: i32); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 ++ StorageLive(_7); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 ++ _7 = move (_2.1: &mut (i32, i32)); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 ++ _5 = &mut ((*_7).1: i32); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 ++ StorageDead(_7); // scope 0 at $DIR/derefer_test.rs:2:11: 7:2 + _0 = const (); // scope 0 at $DIR/derefer_test.rs:2:11: 7:2 + StorageDead(_5); // scope 3 at $DIR/derefer_test.rs:7:1: 7:2 + StorageDead(_4); // scope 2 at $DIR/derefer_test.rs:7:1: 7:2 + StorageDead(_2); // scope 1 at $DIR/derefer_test.rs:7:1: 7:2 + StorageDead(_1); // scope 0 at $DIR/derefer_test.rs:7:1: 7:2 + return; // scope 0 at $DIR/derefer_test.rs:7:2: 7:2 ++ } ++ ++ bb1 (cleanup): { ++ resume; // scope 0 at $DIR/derefer_test.rs:2:1: 7:2 + } + } + diff --git a/src/test/mir-opt/derefer_test.rs b/src/test/mir-opt/derefer_test.rs new file mode 100644 index 0000000000000..2ebc0d343bd74 --- /dev/null +++ b/src/test/mir-opt/derefer_test.rs @@ -0,0 +1,7 @@ +// EMIT_MIR derefer_test.main.Derefer.diff +fn main() { + let mut a = (42,43); + let mut b = (99, &mut a); + let x = &mut (*b.1).0; + let y = &mut (*b.1).1; +} diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir index 9264d41554ae3..a18ff0e35fe9a 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir @@ -10,6 +10,7 @@ fn b(_1: &mut Box) -> &mut T { debug self => _4; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL let mut _5: &mut T; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL let mut _6: &mut T; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + let mut _7: std::boxed::Box; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL } bb0: { @@ -19,7 +20,10 @@ fn b(_1: &mut Box) -> &mut T { _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 StorageLive(_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageLive(_6); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - _6 = &mut (*(*_4)); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + StorageLive(_7); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + _7 = move (*_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + _6 = &mut (*_7); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + StorageDead(_7); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL _5 = &mut (*_6); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL _3 = &mut (*_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageDead(_6); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir index 422bf748d9ffe..d079ba59ffc3d 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir @@ -7,13 +7,17 @@ fn d(_1: &Box) -> &T { let mut _3: &std::boxed::Box; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 scope 1 (inlined as AsRef>::as_ref) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 debug self => _3; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + let mut _4: std::boxed::Box; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL } bb0: { StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 - _2 = &(*(*_3)); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + StorageLive(_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + _4 = move (*_3); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + _2 = &(*_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + StorageDead(_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL _0 = &(*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:14: 18:15 StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:19:1: 19:2 diff --git a/src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff b/src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff index d6c1c92cd9177..2e03467018693 100644 --- a/src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff +++ b/src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff @@ -64,5 +64,9 @@ StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:11:5: 11:6 return; // scope 0 at $DIR/lower_array_len.rs:12:2: 12:2 } + + bb6 (cleanup): { + resume; // scope 0 at $DIR/lower_array_len.rs:6:1: 12:2 + } } diff --git a/src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff b/src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff index 11fc20aa693c7..6aa77a9ed6013 100644 --- a/src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff +++ b/src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff @@ -77,5 +77,9 @@ StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:24:5: 24:6 return; // scope 0 at $DIR/lower_array_len.rs:25:2: 25:2 } + + bb7 (cleanup): { + resume; // scope 0 at $DIR/lower_array_len.rs:17:1: 25:2 + } } diff --git a/src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff b/src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff index 892fdda818ebd..b41582477c692 100644 --- a/src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff +++ b/src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff @@ -26,5 +26,9 @@ StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:31:13: 31:14 return; // scope 0 at $DIR/lower_array_len.rs:32:2: 32:2 } + + bb2 (cleanup): { + resume; // scope 0 at $DIR/lower_array_len.rs:30:1: 32:2 + } } diff --git a/src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff b/src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff index 201fffbf0d45a..92ec7a3633e94 100644 --- a/src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff +++ b/src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff @@ -26,5 +26,9 @@ StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:38:13: 38:14 return; // scope 0 at $DIR/lower_array_len.rs:39:2: 39:2 } + + bb2 (cleanup): { + resume; // scope 0 at $DIR/lower_array_len.rs:37:1: 39:2 + } } diff --git a/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff b/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff index 13241d882f210..2210ad54e8d3d 100644 --- a/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff +++ b/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff @@ -59,5 +59,9 @@ StorageDead(_3); // scope 0 at $DIR/lower_slice_len.rs:9:5: 9:6 return; // scope 0 at $DIR/lower_slice_len.rs:10:2: 10:2 } + + bb6 (cleanup): { + resume; // scope 0 at $DIR/lower_slice_len.rs:4:1: 10:2 + } } diff --git a/src/test/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff b/src/test/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff index 7e843b65e88fc..868eeb6367e33 100644 --- a/src/test/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff +++ b/src/test/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff @@ -9,7 +9,7 @@ bb0: { _2 = discriminant(_1); // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:11: 22:12 - switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:5: 22:12 -+ switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb5]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:5: 22:12 ++ switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:5: 22:12 } bb1: { @@ -29,9 +29,13 @@ bb4: { return; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:27:2: 27:2 + } + + bb5 (cleanup): { + resume; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:21:1: 27:2 + } + -+ bb5: { ++ bb6: { + unreachable; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:25:14: 25:15 } } diff --git a/src/test/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff b/src/test/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff index 5da011d427a2c..33c1458dc0c17 100644 --- a/src/test/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff +++ b/src/test/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff @@ -30,5 +30,9 @@ bb4: { return; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:18:2: 18:2 } + + bb5 (cleanup): { + resume; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:12:1: 18:2 + } } diff --git a/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff index 08312bde20f51..380844f8861f6 100644 --- a/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff +++ b/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff @@ -64,6 +64,10 @@ _0 = const (); // scope 0 at $DIR/unreachable.rs:19:6: 19:6 StorageDead(_1); // scope 0 at $DIR/unreachable.rs:20:1: 20:2 return; // scope 0 at $DIR/unreachable.rs:20:2: 20:2 +- } +- +- bb7 (cleanup): { +- resume; // scope 0 at $DIR/unreachable.rs:8:1: 20:2 } } diff --git a/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff index e5867ccfc5cb6..e26990b1def89 100644 --- a/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff +++ b/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff @@ -69,6 +69,10 @@ StorageDead(_1); // scope 0 at $DIR/unreachable_diverging.rs:20:1: 20:2 StorageDead(_2); // scope 0 at $DIR/unreachable_diverging.rs:20:1: 20:2 return; // scope 0 at $DIR/unreachable_diverging.rs:20:2: 20:2 +- } +- +- bb7 (cleanup): { +- resume; // scope 0 at $DIR/unreachable_diverging.rs:12:1: 20:2 } } diff --git a/src/test/run-make/const_fn_mir/dump.mir b/src/test/run-make/const_fn_mir/dump.mir index f02bccc4b2da5..4e8936905c440 100644 --- a/src/test/run-make/const_fn_mir/dump.mir +++ b/src/test/run-make/const_fn_mir/dump.mir @@ -23,6 +23,10 @@ fn foo() -> i32 { _0 = move (_1.0: i32); // scope 0 at main.rs:5:5: 5:10 return; // scope 0 at main.rs:6:2: 6:2 } + + bb2 (cleanup): { + resume; // scope 0 at main.rs:4:1: 6:2 + } } fn main() -> () {