Change:
Since InstCombine can now introduce where there was none before, without checking that the value is in fact not used afterwards. This may cause a value to be marked as uninitialized by the dataflow, but still be used in that uninitialized state. If InstCombine ran before the generator transform this would be acutely unsound and could probably be exploited directly, but other than that transform I don't think we rely on this property yet. This impacts , which does run after InstCombine and relies on the dataflow. I've observed this on , where it produces this diff: The second use of occurs despite the first move deinitializing the local. cc
Maybe we should stop making instcombine convert to ? This could be done in the pre-codegen cleanups, but for MIR it is wrong to use or on such values in general. Alternatively instcombine needs to start using dataflow to only insert moves when the site is the last use of the local.

Discussion:
//! Performs various peephole optimizations. use crate::transform::{MirPass, MirSource}; <del> use rustc_data_structures::fx::FxHashMap; </del> <ins> use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::Mutability; </ins> use rustc_index::vec::Idx; use rustc_middle::mir::visit::{MutVisitor, Visitor}; use rustc_middle::mir::{ <del> Body, Constant, Local, Location, Mutability, Operand, Place, PlaceRef, ProjectionElem, Rvalue, </del> <ins> Body, Constant, Local, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, </ins> }; use rustc_middle::ty::{self, TyCtxt}; use std::mem;

} fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { <del> if let Some(mtbl) = self.optimizations.and_stars.remove(&location) { </del> <ins> if self.optimizations.and_stars.remove(&location) { </ins> debug!("replacing `&*`: {:?}", rvalue); let new_place = match rvalue { Rvalue::Ref(_, _, place) => {

} _ => bug!("Detected `&*` but didn't find `&*`!"), }; <del> *rvalue = Rvalue::Use(match mtbl { Mutability::Mut => Operand::Move(new_place), Mutability::Not => Operand::Copy(new_place), }); </del> <ins> *rvalue = Rvalue::Use(Operand::Copy(new_place)) </ins> } if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) {

{ // The dereferenced place must have type `&_`. let ty = Place::ty_from(local, proj_base, self.body, self.tcx).ty; <del> if let ty::Ref(_, _, mtbl) = ty.kind { self.optimizations.and_stars.insert(location, mtbl); </del> <ins> if let ty::Ref(_, _, Mutability::Not) = ty.kind { self.optimizations.and_stars.insert(location); </ins> } } }

#[derive(Default)] struct OptimizationList<'tcx> { <del> and_stars: FxHashMap<Location, Mutability>, </del> <ins> and_stars: FxHashSet<Location>, </ins> arrays_lengths: FxHashMap<Location, Constant<'tcx>>, }

let mut _4: &mut [T];                // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:6 scope 1 { debug self => _4;                // in scope 1 at $SRC_DIR/libcore/convert/mod.rs:LL:COL <ins> let mut _5: &mut [T];            // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 </ins> } bb0: {

StorageLive(_3);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 StorageLive(_4);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:6 _4 = &mut (*_1);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:6 <del> _3 = move _4;                    // scope 1 at $SRC_DIR/libcore/convert/mod.rs:LL:COL </del> <ins> StorageLive(_5);                 // scope 1 at $SRC_DIR/libcore/convert/mod.rs:LL:COL _5 = &mut (*_4);                 // scope 1 at $SRC_DIR/libcore/convert/mod.rs:LL:COL _3 = &mut (*_5);                 // scope 1 at $SRC_DIR/libcore/convert/mod.rs:LL:COL StorageDead(_5);                 // scope 1 at $SRC_DIR/libcore/convert/mod.rs:LL:COL </ins> _2 = &mut (*_3);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 StorageDead(_4);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:14: 3:15 _0 = &mut (*_2);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15

scope 1 { debug self => _4;                // in scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL let mut _5: &mut T;              // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 <ins> let mut _6: &mut T;              // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 </ins> } bb0: {

StorageLive(_4);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:6 _4 = &mut (*_1);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:6 StorageLive(_5);                 // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL <del> _5 = &mut (*(*_4));              // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL _3 = move _5;                    // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL </del> <ins> StorageLive(_6);                 // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL _6 = &mut (*(*_4));              // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL _5 = &mut (*_6);                 // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL _3 = &mut (*_5);                 // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL StorageDead(_6);                 // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL </ins> StorageDead(_5);                 // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL _2 = &mut (*_3);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 StorageDead(_4);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:14: 8:15

// + span: $DIR/nrvo-simple.rs:3:20: 3:21 // + literal: Const { ty: u8, val: Value(Scalar(0x00)) } StorageLive(_3);                 // scope 1 at $DIR/nrvo-simple.rs:4:5: 4:19 <ins> StorageLive(_5);                 // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 StorageLive(_6);                 // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 </ins> -         _6 = &mut _2;                    // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 +         _6 = &mut _0;                    // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 <del> _3 = move _1(move _6) -> bb1;    // scope 1 at $DIR/nrvo-simple.rs:4:5: 4:19 </del> <ins> _5 = &mut (*_6);                 // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 _3 = move _1(move _5) -> bb1;    // scope 1 at $DIR/nrvo-simple.rs:4:5: 4:19 </ins> } bb1: { <ins> StorageDead(_5);                 // scope 1 at $DIR/nrvo-simple.rs:4:18: 4:19 StorageDead(_6);                 // scope 1 at $DIR/nrvo-simple.rs:4:19: 4:20 </ins> StorageDead(_3);                 // scope 1 at $DIR/nrvo-simple.rs:4:19: 4:20 -         _0 = _2;                         // scope 1 at $DIR/nrvo-simple.rs:5:5: 5:8 -         StorageDead(_2);                 // scope 0 at $DIR/nrvo-simple.rs:6:1: 6:2