diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 63ee69322eef..e968ed640ecf 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -47,13 +47,21 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { let mut patch = Vec::new(); for (bb, bb_data) in traversal::preorder(body) { - if let TerminatorKind::Call { ref args, .. } = bb_data.terminator().kind { + if let TerminatorKind::Call { ref args, ref destination, .. } = bb_data.terminator().kind { let loc = Location { block: bb, statement_index: bb_data.statements.len() }; // Position ourselves between the evaluation of `args` and the write to `destination`. live.seek_to_block_end(bb); let mut state = live.get().clone(); + // Don't turn into a move if the local is used as an index + // projection for the destination place. + LivenessTransferFunction(&mut state).visit_place( + destination, + visit::PlaceContext::MutatingUse(visit::MutatingUseContext::Call), + loc, + ); + for (index, arg) in args.iter().map(|a| &a.node).enumerate().rev() { if let Operand::Copy(place) = *arg && !place.is_indirect() diff --git a/tests/mir-opt/dead-store-elimination/call_arg_copy.move_index.DeadStoreElimination-final.panic-abort.diff b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_index.DeadStoreElimination-final.panic-abort.diff new file mode 100644 index 000000000000..012dd7d88a5f --- /dev/null +++ b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_index.DeadStoreElimination-final.panic-abort.diff @@ -0,0 +1,15 @@ +- // MIR for `move_index` before DeadStoreElimination-final ++ // MIR for `move_index` after DeadStoreElimination-final + + fn move_index(_1: [usize; 10], _2: usize) -> () { + let mut _0: (); + + bb0: { + _1[_2] = passthrough_usize(copy _2) -> [return: bb1, unwind unreachable]; + } + + bb1: { + return; + } + } + diff --git a/tests/mir-opt/dead-store-elimination/call_arg_copy.move_index.DeadStoreElimination-final.panic-unwind.diff b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_index.DeadStoreElimination-final.panic-unwind.diff new file mode 100644 index 000000000000..fcd0ae43e289 --- /dev/null +++ b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_index.DeadStoreElimination-final.panic-unwind.diff @@ -0,0 +1,15 @@ +- // MIR for `move_index` before DeadStoreElimination-final ++ // MIR for `move_index` after DeadStoreElimination-final + + fn move_index(_1: [usize; 10], _2: usize) -> () { + let mut _0: (); + + bb0: { + _1[_2] = passthrough_usize(copy _2) -> [return: bb1, unwind continue]; + } + + bb1: { + return; + } + } + diff --git a/tests/mir-opt/dead-store-elimination/call_arg_copy.rs b/tests/mir-opt/dead-store-elimination/call_arg_copy.rs index 27b5ccdb936d..00a9a49c2abb 100644 --- a/tests/mir-opt/dead-store-elimination/call_arg_copy.rs +++ b/tests/mir-opt/dead-store-elimination/call_arg_copy.rs @@ -40,7 +40,31 @@ fn move_packed(packed: Packed) { } } +#[inline(never)] +fn passthrough_usize(a: usize) -> usize { + a +} + +// EMIT_MIR call_arg_copy.move_index.DeadStoreElimination-final.diff +#[custom_mir(dialect = "analysis")] +fn move_index(a: [usize; 10], b: usize) { + // CHECK-LABEL: fn move_index( + // CHECK: = passthrough_usize(copy _2) + mir! { + { + // The index is used again after the operand is evaluated to + // evaluate the destionation place, so the argument cannot be turned + // into a move. + Call(a[b] = passthrough_usize(b), ReturnTo(ret), UnwindContinue()) + } + ret = { + Return() + } + } +} + fn main() { move_simple(1); move_packed(Packed { x: 0, y: 1 }); + move_index([0; _], 1); }