diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index ecda524db9ae..6e509f517541 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1908,15 +1908,15 @@ impl<'tcx> Place<'tcx> { // // FIXME: can we safely swap the semantics of `fn base_local` below in here instead? pub fn local_or_deref_local(&self) -> Option { - match self { - Place { - base: PlaceBase::Local(local), - projection: box [], + match self.as_ref() { + PlaceRef { + base: &PlaceBase::Local(local), + projection: &[], } | - Place { - base: PlaceBase::Local(local), - projection: box [ProjectionElem::Deref], - } => Some(*local), + PlaceRef { + base: &PlaceBase::Local(local), + projection: &[ProjectionElem::Deref], + } => Some(local), _ => None, } } diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index ea1cf926fccf..604deffcf949 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -191,10 +191,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> location: Location) { debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue); - if let mir::Place { - base: mir::PlaceBase::Local(index), - projection: box [], - } = *place { + if let Some(index) = place.as_local() { self.assign(index, location); let decl_span = self.fx.mir.local_decls[index].source_info.span; if !self.fx.rvalue_creates_operand(rvalue, decl_span) { diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index dc77d025c005..28441cae26e3 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -2,7 +2,7 @@ use rustc_index::vec::Idx; use rustc::middle::lang_items; use rustc::ty::{self, Ty, TypeFoldable, Instance}; use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt}; -use rustc::mir::{self, Place, PlaceBase, Static, StaticKind}; +use rustc::mir::{self, PlaceBase, Static, StaticKind}; use rustc::mir::interpret::PanicInfo; use rustc_target::abi::call::{ArgType, FnType, PassMode}; use rustc_target::spec::abi::Abi; @@ -630,53 +630,43 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // checked by const-qualification, which also // promotes any complex rvalues to constants. if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") { - match *arg { + match arg { // The shuffle array argument is usually not an explicit constant, // but specified directly in the code. This means it gets promoted // and we can then extract the value by evaluating the promoted. - mir::Operand::Copy( - Place { - base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(promoted, _), + mir::Operand::Copy(place) | mir::Operand::Move(place) => { + if let mir::PlaceRef { + base: + &PlaceBase::Static(box Static { + kind: StaticKind::Promoted(promoted, _), + ty, + def_id: _, + }), + projection: &[], + } = place.as_ref() + { + let param_env = ty::ParamEnv::reveal_all(); + let cid = mir::interpret::GlobalId { + instance: self.instance, + promoted: Some(promoted), + }; + let c = bx.tcx().const_eval(param_env.and(cid)); + let (llval, ty) = self.simd_shuffle_indices( + &bx, + terminator.source_info.span, ty, - def_id: _, - }), - projection: box [], + c, + ); + return OperandRef { + val: Immediate(llval), + layout: bx.layout_of(ty), + }; + } else { + span_bug!(span, "shuffle indices must be constant"); } - ) | - mir::Operand::Move( - Place { - base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(promoted, _), - ty, - def_id: _, - }), - projection: box [], - } - ) => { - let param_env = ty::ParamEnv::reveal_all(); - let cid = mir::interpret::GlobalId { - instance: self.instance, - promoted: Some(promoted), - }; - let c = bx.tcx().const_eval(param_env.and(cid)); - let (llval, ty) = self.simd_shuffle_indices( - &bx, - terminator.source_info.span, - ty, - c, - ); - return OperandRef { - val: Immediate(llval), - layout: bx.layout_of(ty), - }; + } - } - mir::Operand::Copy(_) | - mir::Operand::Move(_) => { - span_bug!(span, "shuffle indices must be constant"); - } - mir::Operand::Constant(ref constant) => { + mir::Operand::Constant(constant) => { let c = self.eval_mir_constant(constant); let (llval, ty) = self.simd_shuffle_indices( &bx, @@ -1117,10 +1107,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if fn_ret.is_ignore() { return ReturnDest::Nothing; } - let dest = if let mir::Place { - base: mir::PlaceBase::Local(index), - projection: box [], - } = *dest { + let dest = if let Some(index) = dest.as_local() { match self.locals[index] { LocalRef::Place(dest) => dest, LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), @@ -1178,10 +1165,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { src: &mir::Operand<'tcx>, dst: &mir::Place<'tcx> ) { - if let mir::Place { - base: mir::PlaceBase::Local(index), - projection: box [], - } = *dst { + if let Some(index) = dst.as_local() { match self.locals[index] { LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place), LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"), diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 7e662ea37dbb..1608f222bc61 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -530,10 +530,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Bx::Value { // ZST are passed as operands and require special handling // because codegen_place() panics if Local is operand. - if let mir::Place { - base: mir::PlaceBase::Local(index), - projection: box [], - } = *place { + if let Some(index) = place.as_local() { if let LocalRef::Operand(Some(op)) = self.locals[index] { if let ty::Array(_, n) = op.layout.ty.kind { let n = n.eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all()); diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs index dab7dfc04175..43d5c2570b70 100644 --- a/src/librustc_codegen_ssa/mir/statement.rs +++ b/src/librustc_codegen_ssa/mir/statement.rs @@ -17,11 +17,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.set_debug_loc(&mut bx, statement.source_info); match statement.kind { mir::StatementKind::Assign(box(ref place, ref rvalue)) => { - if let mir::Place { - base: mir::PlaceBase::Local(index), - projection: box [], - } = place { - match self.locals[*index] { + if let Some(index) = place.as_local() { + match self.locals[index] { LocalRef::Place(cg_dest) => { self.codegen_rvalue(bx, cg_dest, rvalue) } @@ -30,7 +27,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } LocalRef::Operand(None) => { let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue); - if let Some(name) = self.mir.local_decls[*index].name { + if let Some(name) = self.mir.local_decls[index].name { match operand.val { OperandValue::Ref(x, ..) | OperandValue::Immediate(x) => { @@ -44,7 +41,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } - self.locals[*index] = LocalRef::Operand(Some(operand)); + self.locals[index] = LocalRef::Operand(Some(operand)); bx } LocalRef::Operand(Some(op)) => { diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index 7dd1db3b7bdb..98641031c178 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -315,10 +315,7 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> { // TEMP = &foo // // so extract `temp`. - let temp = if let &mir::Place { - base: mir::PlaceBase::Local(temp), - projection: box [], - } = assigned_place { + let temp = if let Some(temp) = assigned_place.as_local() { temp } else { span_bug!( diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index 4c469a82ac3d..9b7a5caa6d91 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -239,11 +239,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } } - let span = if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = place { - let decl = &self.body.local_decls[*local]; + let span = if let Some(local) = place.as_local() { + let decl = &self.body.local_decls[local]; Some(decl.source_info.span) } else { None @@ -611,7 +608,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { projection, } = first_borrowed_place; - let mut cursor = &**projection; + let mut cursor = projection.as_ref(); while let [proj_base @ .., elem] = cursor { cursor = proj_base; @@ -635,7 +632,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { projection, } = second_borrowed_place; - let mut cursor = &**projection; + let mut cursor = projection.as_ref(); while let [proj_base @ .., elem] = cursor { cursor = proj_base; @@ -1124,26 +1121,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }; let (place_desc, note) = if let Some(place_desc) = opt_place_desc { - let local_kind = match borrow.borrowed_place { - Place { - base: PlaceBase::Local(local), - projection: box [], - } => { - match self.body.local_kind(local) { - LocalKind::ReturnPointer - | LocalKind::Temp => bug!("temporary or return pointer with a name"), - LocalKind::Var => "local variable ", - LocalKind::Arg - if !self.upvars.is_empty() - && local == Local::new(1) => { - "variable captured by `move` " - } - LocalKind::Arg => { - "function parameter " - } + let local_kind = if let Some(local) = borrow.borrowed_place.as_local() { + match self.body.local_kind(local) { + LocalKind::ReturnPointer + | LocalKind::Temp => bug!("temporary or return pointer with a name"), + LocalKind::Var => "local variable ", + LocalKind::Arg + if !self.upvars.is_empty() + && local == Local::new(1) => { + "variable captured by `move` " + } + LocalKind::Arg => { + "function parameter " } } - _ => "local data ", + } else { + "local data " }; ( format!("{}`{}`", local_kind, place_desc), @@ -1480,10 +1473,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { assigned_span: Span, err_place: &Place<'tcx>, ) { - let (from_arg, local_decl) = if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = *err_place { + let (from_arg, local_decl) = if let Some(local) = err_place.as_local() { if let LocalKind::Arg = self.body.local_kind(local) { (true, Some(&self.body.local_decls[local])) } else { @@ -1643,11 +1633,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { reservation ); // Check that the initial assignment of the reserve location is into a temporary. - let mut target = *match reservation { - Place { - base: PlaceBase::Local(local), - projection: box [], - } if self.body.local_kind(*local) == LocalKind::Temp => local, + let mut target = match reservation.as_local() { + Some(local) if self.body.local_kind(local) == LocalKind::Temp => local, _ => return None, }; @@ -1659,127 +1646,122 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}", target, stmt ); - if let StatementKind::Assign( - box( - Place { - base: PlaceBase::Local(assigned_to), - projection: box [], - }, - rvalue - ) - ) = &stmt.kind { - debug!( - "annotate_argument_and_return_for_borrow: assigned_to={:?} \ - rvalue={:?}", - assigned_to, rvalue - ); - // Check if our `target` was captured by a closure. - if let Rvalue::Aggregate( - box AggregateKind::Closure(def_id, substs), - operands, - ) = rvalue - { - for operand in operands { - let assigned_from = match operand { + if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind { + if let Some(assigned_to) = place.as_local() { + debug!( + "annotate_argument_and_return_for_borrow: assigned_to={:?} \ + rvalue={:?}", + assigned_to, rvalue + ); + // Check if our `target` was captured by a closure. + if let Rvalue::Aggregate( + box AggregateKind::Closure(def_id, substs), + operands, + ) = rvalue + { + for operand in operands { + let assigned_from = match operand { + Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { + assigned_from + } + _ => continue, + }; + debug!( + "annotate_argument_and_return_for_borrow: assigned_from={:?}", + assigned_from + ); + + // Find the local from the operand. + let assigned_from_local = match assigned_from.local_or_deref_local() + { + Some(local) => local, + None => continue, + }; + + if assigned_from_local != target { + continue; + } + + // If a closure captured our `target` and then assigned + // into a place then we should annotate the closure in + // case it ends up being assigned into the return place. + annotated_closure = self.annotate_fn_sig( + *def_id, + self.infcx.closure_sig(*def_id, *substs), + ); + debug!( + "annotate_argument_and_return_for_borrow: \ + annotated_closure={:?} assigned_from_local={:?} \ + assigned_to={:?}", + annotated_closure, assigned_from_local, assigned_to + ); + + if assigned_to == mir::RETURN_PLACE { + // If it was assigned directly into the return place, then + // return now. + return annotated_closure; + } else { + // Otherwise, update the target. + target = assigned_to; + } + } + + // If none of our closure's operands matched, then skip to the next + // statement. + continue; + } + + // Otherwise, look at other types of assignment. + let assigned_from = match rvalue { + Rvalue::Ref(_, _, assigned_from) => assigned_from, + Rvalue::Use(operand) => match operand { Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { assigned_from } _ => continue, - }; - debug!( - "annotate_argument_and_return_for_borrow: assigned_from={:?}", - assigned_from - ); + }, + _ => continue, + }; + debug!( + "annotate_argument_and_return_for_borrow: \ + assigned_from={:?}", + assigned_from, + ); - // Find the local from the operand. - let assigned_from_local = match assigned_from.local_or_deref_local() { - Some(local) => local, - None => continue, - }; + // Find the local from the rvalue. + let assigned_from_local = match assigned_from.local_or_deref_local() { + Some(local) => local, + None => continue, + }; + debug!( + "annotate_argument_and_return_for_borrow: \ + assigned_from_local={:?}", + assigned_from_local, + ); - if assigned_from_local != target { - continue; - } - - // If a closure captured our `target` and then assigned - // into a place then we should annotate the closure in - // case it ends up being assigned into the return place. - annotated_closure = self.annotate_fn_sig( - *def_id, - self.infcx.closure_sig(*def_id, *substs), - ); - debug!( - "annotate_argument_and_return_for_borrow: \ - annotated_closure={:?} assigned_from_local={:?} \ - assigned_to={:?}", - annotated_closure, assigned_from_local, assigned_to - ); - - if *assigned_to == mir::RETURN_PLACE { - // If it was assigned directly into the return place, then - // return now. - return annotated_closure; - } else { - // Otherwise, update the target. - target = *assigned_to; - } + // Check if our local matches the target - if so, we've assigned our + // borrow to a new place. + if assigned_from_local != target { + continue; } - // If none of our closure's operands matched, then skip to the next - // statement. - continue; + // If we assigned our `target` into a new place, then we should + // check if it was the return place. + debug!( + "annotate_argument_and_return_for_borrow: \ + assigned_from_local={:?} assigned_to={:?}", + assigned_from_local, assigned_to + ); + if assigned_to == mir::RETURN_PLACE { + // If it was then return the annotated closure if there was one, + // else, annotate this function. + return annotated_closure.or_else(fallback); + } + + // If we didn't assign into the return place, then we just update + // the target. + target = assigned_to; } - - // Otherwise, look at other types of assignment. - let assigned_from = match rvalue { - Rvalue::Ref(_, _, assigned_from) => assigned_from, - Rvalue::Use(operand) => match operand { - Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { - assigned_from - } - _ => continue, - }, - _ => continue, - }; - debug!( - "annotate_argument_and_return_for_borrow: \ - assigned_from={:?}", - assigned_from, - ); - - // Find the local from the rvalue. - let assigned_from_local = match assigned_from.local_or_deref_local() { - Some(local) => local, - None => continue, - }; - debug!( - "annotate_argument_and_return_for_borrow: \ - assigned_from_local={:?}", - assigned_from_local, - ); - - // Check if our local matches the target - if so, we've assigned our - // borrow to a new place. - if assigned_from_local != target { - continue; - } - - // If we assigned our `target` into a new place, then we should - // check if it was the return place. - debug!( - "annotate_argument_and_return_for_borrow: \ - assigned_from_local={:?} assigned_to={:?}", - assigned_from_local, assigned_to - ); - if *assigned_to == mir::RETURN_PLACE { - // If it was then return the annotated closure if there was one, - // else, annotate this function. - return annotated_closure.or_else(fallback); - } - - // If we didn't assign into the return place, then we just update - // the target. - target = *assigned_to; } } @@ -1790,38 +1772,37 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { target, terminator ); if let TerminatorKind::Call { - destination: Some((Place { - base: PlaceBase::Local(assigned_to), - projection: box [], - }, _)), + destination: Some((place, _)), args, .. } = &terminator.kind { - debug!( - "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}", - assigned_to, args - ); - for operand in args { - let assigned_from = match operand { - Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { - assigned_from - } - _ => continue, - }; + if let Some(assigned_to) = place.as_local() { debug!( - "annotate_argument_and_return_for_borrow: assigned_from={:?}", - assigned_from, + "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}", + assigned_to, args ); - - if let Some(assigned_from_local) = assigned_from.local_or_deref_local() { + for operand in args { + let assigned_from = match operand { + Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { + assigned_from + } + _ => continue, + }; debug!( - "annotate_argument_and_return_for_borrow: assigned_from_local={:?}", - assigned_from_local, + "annotate_argument_and_return_for_borrow: assigned_from={:?}", + assigned_from, ); - if *assigned_to == mir::RETURN_PLACE && assigned_from_local == target { - return annotated_closure.or_else(fallback); + if let Some(assigned_from_local) = assigned_from.local_or_deref_local() { + debug!( + "annotate_argument_and_return_for_borrow: assigned_from_local={:?}", + assigned_from_local, + ); + + if assigned_to == mir::RETURN_PLACE && assigned_from_local == target { + return annotated_closure.or_else(fallback); + } } } } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 5e0727d51579..4036e9db33b3 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -838,12 +838,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .get(location.statement_index) { Some(&Statement { - kind: StatementKind::Assign(box(Place { - base: PlaceBase::Local(local), - projection: box [], - }, _)), + kind: StatementKind::Assign(box(ref place, _)), .. - }) => local, + }) => { + if let Some(local) = place.as_local() { + local + } else { + return OtherUse(use_span); + } + } _ => return OtherUse(use_span), }; diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 75d4b56fdb7c..c3369e872151 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1133,15 +1133,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Special case: you can assign a immutable local variable // (e.g., `x = ...`) so long as it has never been initialized // before (at this point in the flow). - if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = place_span.0 { - if let Mutability::Not = self.body.local_decls[*local].mutability { + if let Some(local) = place_span.0.as_local() { + if let Mutability::Not = self.body.local_decls[local].mutability { // check for reassignments to immutable local variables self.check_if_reassignment_to_immutable_state( location, - *local, + local, place_span, flow_state, ); @@ -1288,59 +1285,57 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // captures of a closure are copied/moved directly // when generating MIR. match *operand { - Operand::Move(Place { - base: PlaceBase::Local(local), - projection: box [], - }) | - Operand::Copy(Place { - base: PlaceBase::Local(local), - projection: box [], - }) if self.body.local_decls[local].is_user_variable.is_none() => { - if self.body.local_decls[local].ty.is_mutable_ptr() { - // The variable will be marked as mutable by the borrow. - return; + Operand::Move(ref place) | Operand::Copy(ref place) => { + match place.as_local() { + Some(local) if self.body.local_decls[local].is_user_variable.is_none() => { + if self.body.local_decls[local].ty.is_mutable_ptr() { + // The variable will be marked as mutable by the borrow. + return; + } + // This is an edge case where we have a `move` closure + // inside a non-move closure, and the inner closure + // contains a mutation: + // + // let mut i = 0; + // || { move || { i += 1; }; }; + // + // In this case our usual strategy of assuming that the + // variable will be captured by mutable reference is + // wrong, since `i` can be copied into the inner + // closure from a shared reference. + // + // As such we have to search for the local that this + // capture comes from and mark it as being used as mut. + + let temp_mpi = self.move_data.rev_lookup.find_local(local); + let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] { + &self.move_data.inits[init_index] + } else { + bug!("temporary should be initialized exactly once") + }; + + let loc = match init.location { + InitLocation::Statement(stmt) => stmt, + _ => bug!("temporary initialized in arguments"), + }; + + let bbd = &self.body[loc.block]; + let stmt = &bbd.statements[loc.statement_index]; + debug!("temporary assigned in: stmt={:?}", stmt); + + if let StatementKind::Assign(box (_, Rvalue::Ref(_, _, ref source))) = + stmt.kind + { + propagate_closure_used_mut_place(self, source); + } else { + bug!( + "closures should only capture user variables \ + or references to user variables" + ); + } + } + _ => propagate_closure_used_mut_place(self, place), } - // This is an edge case where we have a `move` closure - // inside a non-move closure, and the inner closure - // contains a mutation: - // - // let mut i = 0; - // || { move || { i += 1; }; }; - // - // In this case our usual strategy of assuming that the - // variable will be captured by mutable reference is - // wrong, since `i` can be copied into the inner - // closure from a shared reference. - // - // As such we have to search for the local that this - // capture comes from and mark it as being used as mut. - - let temp_mpi = self.move_data.rev_lookup.find_local(local); - let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] { - &self.move_data.inits[init_index] - } else { - bug!("temporary should be initialized exactly once") - }; - - let loc = match init.location { - InitLocation::Statement(stmt) => stmt, - _ => bug!("temporary initialized in arguments"), - }; - - let bbd = &self.body[loc.block]; - let stmt = &bbd.statements[loc.statement_index]; - debug!("temporary assigned in: stmt={:?}", stmt); - - if let StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref source))) = stmt.kind { - propagate_closure_used_mut_place(self, source); - } else { - bug!("closures should only capture user variables \ - or references to user variables"); - } - } - Operand::Move(ref place) - | Operand::Copy(ref place) => { - propagate_closure_used_mut_place(self, place); } Operand::Constant(..) => {} } @@ -1702,7 +1697,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("check_if_assigned_path_is_moved place: {:?}", place); // None case => assigning to `x` does not require `x` be initialized. - let mut cursor = &*place.projection; + let mut cursor = &*place.projection.as_ref(); while let [proj_base @ .., elem] = cursor { cursor = proj_base; diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index 431361fa5a87..d9e958d94500 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -89,45 +89,41 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // If that ever stops being the case, then the ever initialized // flow could be used. if let Some(StatementKind::Assign( - box( - Place { - base: PlaceBase::Local(local), - projection: box [], - }, - Rvalue::Use(Operand::Move(move_from)) - ) + box(place, Rvalue::Use(Operand::Move(move_from))) )) = self.body.basic_blocks()[location.block] .statements .get(location.statement_index) .map(|stmt| &stmt.kind) { - let local_decl = &self.body.local_decls[*local]; - // opt_match_place is the - // match_span is the span of the expression being matched on - // match *x.y { ... } match_place is Some(*x.y) - // ^^^^ match_span is the span of *x.y - // - // opt_match_place is None for let [mut] x = ... statements, - // whether or not the right-hand side is a place expression - if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { - opt_match_place: Some((ref opt_match_place, match_span)), - binding_mode: _, - opt_ty_info: _, - pat_span: _, - }))) = local_decl.is_user_variable - { - let stmt_source_info = self.body.source_info(location); - self.append_binding_error( - grouped_errors, - kind, - original_path, - move_from, - *local, - opt_match_place, - match_span, - stmt_source_info.span, - ); - return; + if let Some(local) = place.as_local() { + let local_decl = &self.body.local_decls[local]; + // opt_match_place is the + // match_span is the span of the expression being matched on + // match *x.y { ... } match_place is Some(*x.y) + // ^^^^ match_span is the span of *x.y + // + // opt_match_place is None for let [mut] x = ... statements, + // whether or not the right-hand side is a place expression + if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { + opt_match_place: Some((ref opt_match_place, match_span)), + binding_mode: _, + opt_ty_info: _, + pat_span: _, + }))) = local_decl.is_user_variable + { + let stmt_source_info = self.body.source_info(location); + self.append_binding_error( + grouped_errors, + kind, + original_path, + move_from, + local, + opt_match_place, + match_span, + stmt_source_info.span, + ); + return; + } } } @@ -307,11 +303,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All) .find_map(|p| self.is_upvar_field_projection(p)); - let deref_base = match &deref_target_place.projection { - box [proj_base @ .., ProjectionElem::Deref] => { + let deref_base = match deref_target_place.projection.as_ref() { + &[ref proj_base @ .., ProjectionElem::Deref] => { PlaceRef { base: &deref_target_place.base, - projection: proj_base, + projection: &proj_base, } } _ => bug!("deref_target_place is not a deref projection"), diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index 8ab4020394ff..68b33331a1ff 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -49,10 +49,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { projection: [], } => { item_msg = format!("`{}`", access_place_desc.unwrap()); - if let Place { - base: PlaceBase::Local(_), - projection: box [], - } = access_place { + if access_place.as_local().is_some() { reason = ", as it is not declared as mutable".to_string(); } else { let name = self.body.local_decls[*local] @@ -153,10 +150,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }), projection: [], } => { - if let Place { - base: PlaceBase::Static(_), - projection: box [], - } = access_place { + if let PlaceRef { + base: &PlaceBase::Static(_), + projection: &[], + } = access_place.as_ref() { item_msg = format!("immutable static item `{}`", access_place_desc.unwrap()); reason = String::new(); } else { diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index b105664399a5..cae303039a19 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -8,8 +8,8 @@ use rustc::infer::InferCtxt; use rustc::mir::visit::TyContext; use rustc::mir::visit::Visitor; use rustc::mir::{ - BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, ProjectionElem, Rvalue, - SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection, + BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, PlaceRef, ProjectionElem, + Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection, }; use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, RegionVid, Ty}; @@ -211,14 +211,14 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { // - if it's a deeper projection, we have to filter which // of the borrows are killed: the ones whose `borrowed_place` // conflicts with the `place`. - match place { - Place { - base: PlaceBase::Local(local), - projection: box [], + match place.as_ref() { + PlaceRef { + base: &PlaceBase::Local(local), + projection: &[], } | - Place { - base: PlaceBase::Local(local), - projection: box [ProjectionElem::Deref], + PlaceRef { + base: &PlaceBase::Local(local), + projection: &[ProjectionElem::Deref], } => { debug!( "Recording `killed` facts for borrows of local={:?} at location={:?}", @@ -229,21 +229,21 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { all_facts, self.borrow_set, self.location_table, - local, + &local, location, ); } - Place { - base: PlaceBase::Static(_), + PlaceRef { + base: &PlaceBase::Static(_), .. } => { // Ignore kills of static or static mut variables. } - Place { - base: PlaceBase::Local(local), - projection: box [.., _], + PlaceRef { + base: &PlaceBase::Local(local), + projection: &[.., _], } => { // Kill conflicting borrows of the innermost local. debug!( @@ -252,7 +252,7 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { local, location ); - if let Some(borrow_indices) = self.borrow_set.local_map.get(local) { + if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) { for &borrow_index in borrow_indices { let places_conflict = places_conflict::places_conflict( self.infcx.tcx, diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index 59b2796db7ab..26bead3047d5 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -6,8 +6,8 @@ use crate::borrow_check::nll::region_infer::{Cause, RegionName}; use crate::borrow_check::nll::ConstraintDescription; use crate::borrow_check::{MirBorrowckCtxt, WriteKind}; use rustc::mir::{ - CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, PlaceBase, - Rvalue, Statement, StatementKind, TerminatorKind, + CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, Rvalue, + Statement, StatementKind, TerminatorKind, }; use rustc::ty::{self, TyCtxt}; use rustc::ty::adjustment::{PointerCast}; @@ -273,12 +273,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut should_note_order = false; if body.local_decls[local].name.is_some() { if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place { - if let Place { - base: PlaceBase::Local(borrowed_local), - projection: box [], - } = place { - if body.local_decls[*borrowed_local].name.is_some() - && local != *borrowed_local + if let Some(borrowed_local) = place.as_local() { + if body.local_decls[borrowed_local].name.is_some() + && local != borrowed_local { should_note_order = true; } @@ -494,22 +491,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Just point to the function, to reduce the chance of overlapping spans. let function_span = match func { Operand::Constant(c) => c.span, - Operand::Copy(Place { - base: PlaceBase::Local(l), - projection: box [], - }) | - Operand::Move(Place { - base: PlaceBase::Local(l), - projection: box [], - }) => { - let local_decl = &self.body.local_decls[*l]; - if local_decl.name.is_none() { - local_decl.source_info.span + Operand::Copy(place) | + Operand::Move(place) => { + if let Some(l) = place.as_local() { + let local_decl = &self.body.local_decls[l]; + if local_decl.name.is_none() { + local_decl.source_info.span + } else { + span + } } else { span } } - _ => span, }; return (LaterUseKind::Call, function_span); } else { @@ -542,14 +536,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // it which simplifies the termination logic. let mut queue = vec![location]; let mut target = if let Some(&Statement { - kind: StatementKind::Assign(box(Place { - base: PlaceBase::Local(local), - projection: box [], - }, _)), + kind: StatementKind::Assign(box(ref place, _)), .. - }) = stmt - { - local + }) = stmt { + if let Some(local) = place.as_local() { + local + } else { + return false; + } } else { return false; }; @@ -582,17 +576,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // If we see a use, we should check whether it is our data, and if so // update the place that we're looking for to that new place. Rvalue::Use(operand) => match operand { - Operand::Copy(Place { - base: PlaceBase::Local(from), - projection: box [], - }) - | Operand::Move(Place { - base: PlaceBase::Local(from), - projection: box [], - }) - if *from == target => - { - target = into; + Operand::Copy(place) + | Operand::Move(place) => { + if let Some(from) = place.as_local() { + if from == target { + target = into; + } + } } _ => {} }, @@ -601,28 +591,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Rvalue::Cast( CastKind::Pointer(PointerCast::Unsize), operand, ty ) => match operand { - Operand::Copy(Place { - base: PlaceBase::Local(from), - projection: box [], - }) - | Operand::Move(Place { - base: PlaceBase::Local(from), - projection: box [], - }) - if *from == target => - { - debug!("was_captured_by_trait_object: ty={:?}", ty); - // Check the type for a trait object. - return match ty.kind { - // `&dyn Trait` - ty::Ref(_, ty, _) if ty.is_trait() => true, - // `Box` - _ if ty.is_box() && ty.boxed_ty().is_trait() => true, - // `dyn Trait` - _ if ty.is_trait() => true, - // Anything else. - _ => false, - }; + Operand::Copy(place) + | Operand::Move(place) => { + if let Some(from) = place.as_local() { + if from == target { + debug!("was_captured_by_trait_object: ty={:?}", ty); + // Check the type for a trait object. + return match ty.kind { + // `&dyn Trait` + ty::Ref(_, ty, _) if ty.is_trait() => true, + // `Box` + _ if ty.is_box() && ty.boxed_ty().is_trait() => true, + // `dyn Trait` + _ if ty.is_trait() => true, + // Anything else. + _ => false, + }; + } + } + return false; } _ => return false, }, @@ -638,34 +625,33 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("was_captured_by_trait_object: terminator={:?}", terminator); if let TerminatorKind::Call { - destination: Some((Place { - base: PlaceBase::Local(dest), - projection: box [], - }, block)), + destination: Some((place, block)), args, .. - } = &terminator.kind - { - debug!( - "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", - target, dest, args - ); - // Check if one of the arguments to this function is the target place. - let found_target = args.iter().any(|arg| { - if let Operand::Move(Place { - base: PlaceBase::Local(potential), - projection: box [], - }) = arg { - *potential == target - } else { - false - } - }); + } = &terminator.kind { + if let Some(dest) = place.as_local() { + debug!( + "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", + target, dest, args + ); + // Check if one of the arguments to this function is the target place. + let found_target = args.iter().any(|arg| { + if let Operand::Move(place) = arg { + if let Some(potential) = place.as_local() { + potential == target + } else { + false + } + } else { + false + } + }); - // If it is, follow this to the next block and update the target. - if found_target { - target = *dest; - queue.push(block.start_location()); + // If it is, follow this to the next block and update the target. + if found_target { + target = dest; + queue.push(block.start_location()); + } } } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index ed639e8eee77..b5560fe6751b 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -480,13 +480,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { if place.projection.is_empty() { if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { - let is_promoted = match place { - Place { - base: PlaceBase::Static(box Static { + let is_promoted = match place.as_ref() { + PlaceRef { + base: &PlaceBase::Static(box Static { kind: StaticKind::Promoted(..), .. }), - projection: box [], + projection: &[], } => true, _ => false, }; @@ -1366,11 +1366,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // they are not caused by the user, but rather artifacts // of lowering. Assignments to other sorts of places *are* interesting // though. - let category = match *place { - Place { - base: PlaceBase::Local(RETURN_PLACE), - projection: box [], - } => if let BorrowCheckContext { + let category = match place.as_local() { + Some(RETURN_PLACE) => if let BorrowCheckContext { universal_regions: UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), @@ -1386,10 +1383,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } else { ConstraintCategory::Return }, - Place { - base: PlaceBase::Local(l), - projection: box [], - } if !body.local_decls[l].is_user_variable.is_some() => { + Some(l) if !body.local_decls[l].is_user_variable.is_some() => { ConstraintCategory::Boring } _ => ConstraintCategory::Assignment, @@ -1675,11 +1669,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some((ref dest, _target_block)) => { let dest_ty = dest.ty(body, tcx).ty; let dest_ty = self.normalize(dest_ty, term_location); - let category = match *dest { - Place { - base: PlaceBase::Local(RETURN_PLACE), - projection: box [], - } => { + let category = match dest.as_local() { + Some(RETURN_PLACE) => { if let BorrowCheckContext { universal_regions: UniversalRegions { @@ -1698,10 +1689,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::Return } } - Place { - base: PlaceBase::Local(l), - projection: box [], - } if !body.local_decls[l].is_user_variable.is_some() => { + Some(l) if !body.local_decls[l].is_user_variable.is_some() => { ConstraintCategory::Boring } _ => ConstraintCategory::Assignment, @@ -2432,7 +2420,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { location, borrow_region, borrowed_place ); - let mut cursor = &*borrowed_place.projection; + let mut cursor = borrowed_place.projection.as_ref(); while let [proj_base @ .., elem] = cursor { cursor = proj_base; diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 9dd3e119c217..264e4807af07 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -64,14 +64,8 @@ pub(super) fn borrow_conflicts_with_place<'tcx>( // This Local/Local case is handled by the more general code below, but // it's so common that it's a speed win to check for it first. - if let Place { - base: PlaceBase::Local(l1), - projection: box [], - } = borrow_place { - if let PlaceRef { - base: PlaceBase::Local(l2), - projection: [], - } = access_place { + if let Some(l1) = borrow_place.as_local() { + if let Some(l2) = access_place.as_local() { return l1 == l2; } } diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs index 695080dfe23d..95471afb7884 100644 --- a/src/librustc_mir/borrow_check/used_muts.rs +++ b/src/librustc_mir/borrow_check/used_muts.rs @@ -1,7 +1,5 @@ use rustc::mir::visit::{PlaceContext, Visitor}; -use rustc::mir::{ - Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind -}; +use rustc::mir::{Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind}; use rustc_data_structures::fx::FxHashSet; @@ -118,10 +116,7 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc "assignment of {:?} to {:?}, adding {:?} to used mutable set", path.place, local, path.place ); - if let Place { - base: PlaceBase::Local(user_local), - projection: box [], - } = path.place { + if let Some(user_local) = path.place.as_local() { self.mbcx.used_mut.insert(user_local); } } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 87d95a751534..43ee6557634f 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -496,14 +496,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let arg_place = unpack!(block = this.as_place(block, arg)); - let mutability = match arg_place { - Place { - base: PlaceBase::Local(local), - projection: box [], + let mutability = match arg_place.as_ref() { + PlaceRef { + base: &PlaceBase::Local(local), + projection: &[], } => this.local_decls[local].mutability, - Place { - base: PlaceBase::Local(local), - projection: box [ProjectionElem::Deref], + PlaceRef { + base: &PlaceBase::Local(local), + projection: &[ProjectionElem::Deref], } => { debug_assert!( this.local_decls[local].is_ref_for_guard(), @@ -511,13 +511,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); this.local_decls[local].mutability } - Place { + PlaceRef { ref base, - projection: box [ref proj_base @ .., ProjectionElem::Field(upvar_index, _)], + projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _)], } - | Place { + | PlaceRef { ref base, - projection: box [ + projection: &[ ref proj_base @ .., ProjectionElem::Field(upvar_index, _), ProjectionElem::Deref diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 2e451fc88d95..b86bb21f6e39 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -1293,7 +1293,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Insert a Shallow borrow of the prefixes of any fake borrows. for place in fake_borrows { - let mut cursor = &*place.projection; + let mut cursor = place.projection.as_ref(); while let [proj_base @ .., elem] = cursor { cursor = proj_base; diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index a749b4263ea6..1b3d8641f204 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -926,46 +926,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // If constants and statics, we don't generate StorageLive for this // temporary, so don't try to generate StorageDead for it either. _ if self.local_scope().is_none() => (), - Operand::Copy(Place { - base: PlaceBase::Local(cond_temp), - projection: box [], - }) - | Operand::Move(Place { - base: PlaceBase::Local(cond_temp), - projection: box [], - }) => { - // Manually drop the condition on both branches. - let top_scope = self.scopes.scopes.last_mut().unwrap(); - let top_drop_data = top_scope.drops.pop().unwrap(); + Operand::Copy(place) + | Operand::Move(place) => { + if let Some(cond_temp) = place.as_local() { + // Manually drop the condition on both branches. + let top_scope = self.scopes.scopes.last_mut().unwrap(); + let top_drop_data = top_scope.drops.pop().unwrap(); - match top_drop_data.kind { - DropKind::Value { .. } => { - bug!("Drop scheduled on top of condition variable") - } - DropKind::Storage => { - let source_info = top_scope.source_info(top_drop_data.span); - let local = top_drop_data.local; - assert_eq!(local, cond_temp, "Drop scheduled on top of condition"); - self.cfg.push( - true_block, - Statement { - source_info, - kind: StatementKind::StorageDead(local) - }, - ); - self.cfg.push( - false_block, - Statement { - source_info, - kind: StatementKind::StorageDead(local) - }, - ); + match top_drop_data.kind { + DropKind::Value { .. } => { + bug!("Drop scheduled on top of condition variable") + } + DropKind::Storage => { + let source_info = top_scope.source_info(top_drop_data.span); + let local = top_drop_data.local; + assert_eq!(local, cond_temp, "Drop scheduled on top of condition"); + self.cfg.push( + true_block, + Statement { + source_info, + kind: StatementKind::StorageDead(local) + }, + ); + self.cfg.push( + false_block, + Statement { + source_info, + kind: StatementKind::StorageDead(local) + }, + ); + } } + + top_scope.invalidate_cache(true, self.is_generator, true); + } else { + bug!("Expected as_local_operand to produce a temporary"); } - - top_scope.invalidate_cache(true, self.is_generator, true); } - _ => bug!("Expected as_local_operand to produce a temporary"), } (true_block, false_block) diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs index c1695ba66d0d..1b81032bfe62 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs @@ -157,10 +157,12 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> { // Since `propagate_call_unwind` doesn't exist, we have to kill the // destination here, and then gen it again in `propagate_call_return`. if let TerminatorKind::Call { - destination: Some((Place { base: PlaceBase::Local(local), projection: box [] }, _)), + destination: Some((ref place, _)), .. } = self.body[loc.block].terminator().kind { - sets.kill(local); + if let Some(local) = place.as_local() { + sets.kill(local); + } } self.check_for_move(sets, loc); } diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index f5a03316d809..b599f4799446 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -327,7 +327,7 @@ impl<'tcx> MoveData<'tcx> { pub fn base_local(&self, mut mpi: MovePathIndex) -> Option { loop { let path = &self.move_paths[mpi]; - if let Place { base: PlaceBase::Local(l), projection: box [] } = path.place { + if let Some(l) = path.place.as_local() { return Some(l); } if let Some(parent) = path.parent { diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs index 40007eb3c4a3..c8605e22e108 100644 --- a/src/librustc_mir/transform/check_consts/qualifs.rs +++ b/src/librustc_mir/transform/check_consts/qualifs.rs @@ -164,8 +164,8 @@ pub trait Qualif { Rvalue::Ref(_, _, ref place) => { // Special-case reborrows to be more like a copy of the reference. - if let box [proj_base @ .., elem] = &place.projection { - if ProjectionElem::Deref == *elem { + if let &[ref proj_base @ .., elem] = place.projection.as_ref() { + if ProjectionElem::Deref == elem { let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty; if let ty::Ref(..) = base_ty.kind { return Self::in_place(cx, per_local, PlaceRef { diff --git a/src/librustc_mir/transform/check_consts/resolver.rs b/src/librustc_mir/transform/check_consts/resolver.rs index 4fa4eba4c23b..fc9290d63801 100644 --- a/src/librustc_mir/transform/check_consts/resolver.rs +++ b/src/librustc_mir/transform/check_consts/resolver.rs @@ -56,16 +56,16 @@ where fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) { debug_assert!(!place.is_indirect()); - match (value, place) { - (true, mir::Place { base: mir::PlaceBase::Local(local), .. }) => { - self.qualifs_per_local.insert(*local); + match (value, place.as_ref()) { + (true, mir::PlaceRef { base: &mir::PlaceBase::Local(local), .. }) => { + self.qualifs_per_local.insert(local); } // For now, we do not clear the qualif if a local is overwritten in full by // an unqualified rvalue (e.g. `y = 5`). This is to be consistent // with aggregates where we overwrite all fields with assignments, which would not // get this feature. - (false, mir::Place { base: mir::PlaceBase::Local(_local), projection: box [] }) => { + (false, mir::PlaceRef { base: &mir::PlaceBase::Local(_local), projection: &[] }) => { // self.qualifs_per_local.remove(*local); } @@ -101,11 +101,10 @@ where // If a local with no projections is moved from (e.g. `x` in `y = x`), record that // it no longer needs to be dropped. - if let mir::Operand::Move(mir::Place { - base: mir::PlaceBase::Local(local), - projection: box [], - }) = *operand { - self.qualifs_per_local.remove(local); + if let mir::Operand::Move(place) = operand { + if let Some(local) = place.as_local() { + self.qualifs_per_local.remove(local); + } } } diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 87cd39b02cd9..76a73adf0383 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -244,8 +244,8 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { if let Rvalue::Ref(_, kind, ref place) = *rvalue { // Special-case reborrows to be more like a copy of a reference. let mut reborrow_place = None; - if let box [proj_base @ .., elem] = &place.projection { - if *elem == ProjectionElem::Deref { + if let &[ref proj_base @ .., elem] = place.projection.as_ref() { + if elem == ProjectionElem::Deref { let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty; if let ty::Ref(..) = base_ty.kind { reborrow_place = Some(proj_base); @@ -376,12 +376,15 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { ); if rvalue_has_mut_interior { - let is_derived_from_illegal_borrow = match *borrowed_place { + let is_derived_from_illegal_borrow = match borrowed_place.as_local() { // If an unprojected local was borrowed and its value was the result of an // illegal borrow, suppress this error and mark the result of this borrow as // illegal as well. - Place { base: PlaceBase::Local(borrowed_local), projection: box [] } - if self.derived_from_illegal_borrow.contains(borrowed_local) => true, + Some(borrowed_local) + if self.derived_from_illegal_borrow.contains(borrowed_local) => + { + true + } // Otherwise proceed normally: check the legality of a mutable borrow in this // context. @@ -394,7 +397,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { // FIXME: should we also clear `derived_from_illegal_borrow` when a local is // assigned a new value? if is_derived_from_illegal_borrow { - if let Place { base: PlaceBase::Local(dest), projection: box [] } = *dest { + if let Some(dest) = dest.as_local() { self.derived_from_illegal_borrow.insert(dest); } } @@ -571,10 +574,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { return; } - let needs_drop = if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = *dropped_place { + let needs_drop = if let Some(local) = dropped_place.as_local() { // Use the span where the local was declared as the span of the drop error. err_span = self.body.local_decls[local].source_info.span; self.qualifs.needs_drop.contains(local) diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 70855d70228b..029754dede22 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -407,8 +407,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { place: &Place<'tcx>, is_mut_use: bool, ) { - let mut cursor = &*place.projection; - while let [proj_base @ .., elem] = cursor { + let mut cursor = place.projection.as_ref(); + while let &[ref proj_base @ .., elem] = cursor { cursor = proj_base; match elem { diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 108c6c9786b2..dc6cb9650f05 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -7,10 +7,9 @@ use std::cell::Cell; use rustc::hir::def::DefKind; use rustc::hir::def_id::DefId; use rustc::mir::{ - AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, - Local, UnOp, StatementKind, Statement, LocalKind, - TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, - SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock, + AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, Local, UnOp, + StatementKind, Statement, LocalKind, TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, + BinOp, SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock, }; use rustc::mir::visit::{ Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext, @@ -525,18 +524,21 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // (e.g. for CTFE) it can never happen. But here in const_prop // unknown data is uninitialized, so if e.g. a function argument is unsized // and has a reference taken, we get an ICE. - Rvalue::Ref(_, _, Place { base: PlaceBase::Local(local), projection: box [] }) => { - trace!("checking Ref({:?})", place); - let alive = - if let LocalValue::Live(_) = self.ecx.frame().locals[*local].value { - true - } else { - false - }; + Rvalue::Ref(_, _, place_ref) => { + trace!("checking Ref({:?})", place_ref); - if !alive { - trace!("skipping Ref({:?}) to uninitialized local", place); - return None; + if let Some(local) = place_ref.as_local() { + let alive = + if let LocalValue::Live(_) = self.ecx.frame().locals[local].value { + true + } else { + false + }; + + if !alive { + trace!("skipping Ref({:?}) to uninitialized local", place); + return None; + } } } @@ -706,10 +708,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { .ty(&self.local_decls, self.tcx) .ty; if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) { - if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = *place { + if let Some(local) = place.as_local() { let source = statement.source_info; if let Some(()) = self.const_prop(rval, place_layout, source, place) { if self.can_const_prop[local] { diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 28f97f41b50c..c20726eceba9 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -19,9 +19,7 @@ //! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the //! future. -use rustc::mir::{ - Constant, Local, LocalKind, Location, Place, PlaceBase, Body, Operand, Rvalue, StatementKind -}; +use rustc::mir::{Constant, Local, LocalKind, Location, Place, Body, Operand, Rvalue, StatementKind}; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; use crate::transform::{MirPass, MirSource}; @@ -92,28 +90,32 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation { }; // That use of the source must be an assignment. - match statement.kind { - StatementKind::Assign( - box( - Place { - base: PlaceBase::Local(local), - projection: box [], - }, - Rvalue::Use(ref operand) - ) - ) if local == dest_local => { - let maybe_action = match *operand { - Operand::Copy(ref src_place) | - Operand::Move(ref src_place) => { - Action::local_copy(&body, &def_use_analysis, src_place) + match &statement.kind { + StatementKind::Assign(box(place, Rvalue::Use(operand))) => { + if let Some(local) = place.as_local() { + if local == dest_local { + let maybe_action = match operand { + Operand::Copy(ref src_place) | + Operand::Move(ref src_place) => { + Action::local_copy(&body, &def_use_analysis, src_place) + } + Operand::Constant(ref src_constant) => { + Action::constant(src_constant) + } + }; + match maybe_action { + Some(this_action) => action = this_action, + None => continue, + } + } else { + debug!(" Can't copy-propagate local: source use is not an \ + assignment"); + continue } - Operand::Constant(ref src_constant) => { - Action::constant(src_constant) - } - }; - match maybe_action { - Some(this_action) => action = this_action, - None => continue, + } else { + debug!(" Can't copy-propagate local: source use is not an \ + assignment"); + continue } } _ => { @@ -148,31 +150,20 @@ fn eliminate_self_assignments( for def in dest_use_info.defs_not_including_drop() { let location = def.location; if let Some(stmt) = body[location.block].statements.get(location.statement_index) { - match stmt.kind { - StatementKind::Assign( - box( - Place { - base: PlaceBase::Local(local), - projection: box [], - }, - Rvalue::Use(Operand::Copy(Place { - base: PlaceBase::Local(src_local), - projection: box [], - })), - ) - ) | - StatementKind::Assign( - box( - Place { - base: PlaceBase::Local(local), - projection: box [], - }, - Rvalue::Use(Operand::Move(Place { - base: PlaceBase::Local(src_local), - projection: box [], - })), - ) - ) if local == dest_local && dest_local == src_local => {} + match &stmt.kind { + StatementKind::Assign(box (place, Rvalue::Use(Operand::Copy(src_place)))) + | StatementKind::Assign(box (place, Rvalue::Use(Operand::Move(src_place)))) => { + if let (Some(local), Some(src_local)) = + (place.as_local(), src_place.as_local()) + { + if local == dest_local && dest_local == src_local { + } else { + continue; + } + } else { + continue; + } + } _ => { continue; } @@ -198,10 +189,7 @@ impl<'tcx> Action<'tcx> { fn local_copy(body: &Body<'tcx>, def_use_analysis: &DefUseAnalysis, src_place: &Place<'tcx>) -> Option> { // The source must be a local. - let src_local = if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = *src_place { + let src_local = if let Some(local) = src_place.as_local() { local } else { debug!(" Can't copy-propagate local: source is not a local"); @@ -354,15 +342,18 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> { fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { self.super_operand(operand, location); - match *operand { - Operand::Copy(Place { - base: PlaceBase::Local(local), - projection: box [], - }) | - Operand::Move(Place { - base: PlaceBase::Local(local), - projection: box [], - }) if local == self.dest_local => {} + match operand { + Operand::Copy(place) | + Operand::Move(place) => { + if let Some(local) = place.as_local() { + if local == self.dest_local { + } else { + return; + } + } else { + return; + } + } _ => return, } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 6533e3c5ba81..d0cb1b8297a5 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -864,17 +864,24 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut for (block, block_data) in body.basic_blocks().iter_enumerated() { let (target, unwind, source_info) = match block_data.terminator() { - &Terminator { + Terminator { source_info, kind: TerminatorKind::Drop { - location: Place { - base: PlaceBase::Local(local), - projection: box [], - }, + location, target, unwind } - } if local == gen => (target, unwind, source_info), + } => { + if let Some(local) = location.as_local() { + if local == gen { + (target, unwind, source_info) + } else { + continue; + } + } else { + continue; + } + } _ => continue, }; let unwind = if block_data.is_cleanup { @@ -884,10 +891,10 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut }; elaborate_drop( &mut elaborator, - source_info, + *source_info, &Place::from(gen), (), - target, + *target, unwind, block, ); diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 0cbdcedff478..353d89cf0866 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -587,13 +587,12 @@ impl Inliner<'tcx> { // FIXME: Analysis of the usage of the arguments to avoid // unnecessary temporaries. - if let Operand::Move(Place { - base: PlaceBase::Local(local), - projection: box [], - }) = arg { - if caller_body.local_kind(local) == LocalKind::Temp { - // Reuse the operand if it's a temporary already - return local; + if let Operand::Move(place) = &arg { + if let Some(local) = place.as_local() { + if caller_body.local_kind(local) == LocalKind::Temp { + // Reuse the operand if it's a temporary already + return local; + } } } @@ -650,14 +649,9 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> { fn make_integrate_local(&self, local: &Local) -> Local { if *local == RETURN_PLACE { - match self.destination { - Place { - base: PlaceBase::Local(l), - projection: box [], - } => { - return l; - }, - ref place => bug!("Return place is {:?}, not local", place) + match self.destination.as_local() { + Some(l) => return l, + ref place => bug!("Return place is {:?}, not local", place), } } @@ -686,17 +680,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { context: PlaceContext, location: Location, ) { - match place { - Place { - base: PlaceBase::Local(RETURN_PLACE), - projection: box [], - } => { - // Return pointer; update the place itself - *place = self.destination.clone(); - }, - _ => { - self.super_place(place, context, location); - } + if let Some(RETURN_PLACE) = place.as_local() { + // Return pointer; update the place itself + *place = self.destination.clone(); + } else { + self.super_place(place, context, location); } } diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index bb98d63b1ee1..08668716fee1 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -1,7 +1,8 @@ //! Performs various peephole optimizations. -use rustc::mir::{Constant, Location, Place, PlaceBase, Body, Operand, ProjectionElem, Rvalue, - Local}; +use rustc::mir::{ + Constant, Location, Place, PlaceBase, PlaceRef, Body, Operand, ProjectionElem, Rvalue, Local +}; use rustc::mir::visit::{MutVisitor, Visitor}; use rustc::ty::{self, TyCtxt}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; @@ -40,20 +41,18 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { if self.optimizations.and_stars.remove(&location) { debug!("replacing `&*`: {:?}", rvalue); - let new_place = match *rvalue { - Rvalue::Ref(_, _, Place { - ref mut base, - projection: ref mut projection @ box [.., _], - }) => { - if let box [proj_l @ .., proj_r] = projection { - let place = Place { - // Replace with dummy - base: mem::replace(base, PlaceBase::Local(Local::new(0))), - projection: proj_l.to_vec().into_boxed_slice(), - }; - *projection = vec![proj_r.clone()].into_boxed_slice(); + let new_place = match rvalue { + Rvalue::Ref(_, _, place) => { + if let &[ref proj_l @ .., proj_r] = place.projection.as_ref() { + let new_projection = proj_l.to_vec().into_boxed_slice(); - place + place.projection = vec![proj_r.clone()].into_boxed_slice(); + + Place { + // Replace with dummy + base: mem::replace(&mut place.base, PlaceBase::Local(Local::new(0))), + projection: new_projection, + } } else { unreachable!(); } @@ -91,12 +90,14 @@ impl OptimizationFinder<'b, 'tcx> { impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - if let Rvalue::Ref(_, _, Place { - base, - projection: box [proj_base @ .., ProjectionElem::Deref], - }) = rvalue { - if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() { - self.optimizations.and_stars.insert(location); + if let Rvalue::Ref(_, _, place) = rvalue { + if let PlaceRef { + base, + projection: &[ref proj_base @ .., ProjectionElem::Deref], + } = place.as_ref() { + if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() { + self.optimizations.and_stars.insert(location); + } } } diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index ad1785417cd9..f13d49e3f54f 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -434,14 +434,13 @@ pub fn promote_candidates<'tcx>( match candidate { Candidate::Repeat(Location { block, statement_index }) | Candidate::Ref(Location { block, statement_index }) => { - match body[block].statements[statement_index].kind { - StatementKind::Assign(box(Place { - base: PlaceBase::Local(local), - projection: box [], - }, _)) => { - if temps[local] == TempState::PromotedOut { - // Already promoted. - continue; + match &body[block].statements[statement_index].kind { + StatementKind::Assign(box(place, _)) => { + if let Some(local) = place.as_local() { + if temps[local] == TempState::PromotedOut { + // Already promoted. + continue; + } } } _ => {} @@ -487,28 +486,30 @@ pub fn promote_candidates<'tcx>( let promoted = |index: Local| temps[index] == TempState::PromotedOut; for block in body.basic_blocks_mut() { block.statements.retain(|statement| { - match statement.kind { - StatementKind::Assign(box(Place { - base: PlaceBase::Local(index), - projection: box [], - }, _)) | + match &statement.kind { + StatementKind::Assign(box(place, _)) => { + if let Some(index) = place.as_local() { + !promoted(index) + } else { + true + } + } StatementKind::StorageLive(index) | StatementKind::StorageDead(index) => { - !promoted(index) + !promoted(*index) } _ => true } }); let terminator = block.terminator_mut(); - match terminator.kind { - TerminatorKind::Drop { location: Place { - base: PlaceBase::Local(index), - projection: box [], - }, target, .. } => { - if promoted(index) { - terminator.kind = TerminatorKind::Goto { - target, - }; + match &terminator.kind { + TerminatorKind::Drop { location: place, target, .. } => { + if let Some(index) = place.as_local() { + if promoted(index) { + terminator.kind = TerminatorKind::Goto { + target: *target, + }; + } } } _ => {} diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index da1abb9747c1..6aba91f41629 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -292,8 +292,8 @@ trait Qualif { Rvalue::Ref(_, _, ref place) => { // Special-case reborrows to be more like a copy of the reference. - if let box [proj_base @ .., elem] = &place.projection { - if ProjectionElem::Deref == *elem { + if let &[ref proj_base @ .., elem] = place.projection.as_ref() { + if ProjectionElem::Deref == elem { let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty; if let ty::Ref(..) = base_ty.kind { return Self::in_place(cx, PlaceRef { @@ -1041,26 +1041,24 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { match *candidate { Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => { if let StatementKind::Assign(box(_, Rvalue::Repeat( - Operand::Move(Place { - base: PlaceBase::Local(index), - projection: box [], - }), + Operand::Move(place), _ - ))) = self.body[bb].statements[stmt_idx].kind { - promoted_temps.insert(index); + ))) = &self.body[bb].statements[stmt_idx].kind { + if let Some(index) = place.as_local() { + promoted_temps.insert(index); + } } } Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => { if let StatementKind::Assign( box( _, - Rvalue::Ref(_, _, Place { - base: PlaceBase::Local(index), - projection: box [], - }) + Rvalue::Ref(_, _, place) ) - ) = self.body[bb].statements[stmt_idx].kind { - promoted_temps.insert(index); + ) = &self.body[bb].statements[stmt_idx].kind { + if let Some(index) = place.as_local() { + promoted_temps.insert(index); + } } } Candidate::Argument { .. } => {} @@ -1237,10 +1235,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { match *operand { Operand::Move(ref place) => { // Mark the consumed locals to indicate later drops are noops. - if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = *place { + if let Some(local) = place.as_local() { self.cx.per_local[NeedsDrop].remove(local); } } @@ -1256,8 +1251,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { if let Rvalue::Ref(_, kind, ref place) = *rvalue { // Special-case reborrows. let mut reborrow_place = None; - if let box [proj_base @ .., elem] = &place.projection { - if *elem == ProjectionElem::Deref { + if let &[ref proj_base @ .., elem] = place.projection.as_ref() { + if elem == ProjectionElem::Deref { let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty; if let ty::Ref(..) = base_ty.kind { reborrow_place = Some(proj_base); @@ -1568,10 +1563,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { unleash_miri!(self); // HACK(eddyb): emulate a bit of dataflow analysis, // conservatively, that drop elaboration will do. - let needs_drop = if let Place { - base: PlaceBase::Local(local), - projection: box [], - } = *place { + let needs_drop = if let Some(local) = place.as_local() { if NeedsDrop::in_local(self, local) { Some(self.body.local_decls[local].source_info.span) } else { @@ -1817,16 +1809,17 @@ fn remove_drop_and_storage_dead_on_promoted_locals( } }); let terminator = block.terminator_mut(); - match terminator.kind { + match &terminator.kind { TerminatorKind::Drop { - location: Place { - base: PlaceBase::Local(index), - projection: box [], - }, + location, target, .. - } if promoted_temps.contains(index) => { - terminator.kind = TerminatorKind::Goto { target }; + } => { + if let Some(index) = location.as_local() { + if promoted_temps.contains(index) { + terminator.kind = TerminatorKind::Goto { target: *target }; + } + } } _ => {} } diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 7b6255defd14..c4e44091bc90 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -259,8 +259,8 @@ fn check_place( def_id: DefId, body: &Body<'tcx> ) -> McfResult { - let mut cursor = &*place.projection; - while let [proj_base @ .., elem] = cursor { + let mut cursor = place.projection.as_ref(); + while let &[ref proj_base @ .., elem] = cursor { cursor = proj_base; match elem { ProjectionElem::Downcast(..) => { diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index e1994c5f639b..130393e2c4c8 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -32,7 +32,7 @@ impl RemoveNoopLandingPads { nop_landing_pads: &BitSet, ) -> bool { for stmt in &body[bb].statements { - match stmt.kind { + match &stmt.kind { StatementKind::FakeRead(..) | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | @@ -41,12 +41,13 @@ impl RemoveNoopLandingPads { // These are all nops in a landing pad } - StatementKind::Assign(box(Place { - base: PlaceBase::Local(_), - projection: box [], - }, Rvalue::Use(_))) => { - // Writing to a local (e.g., a drop flag) does not - // turn a landing pad to a non-nop + StatementKind::Assign(box(place, Rvalue::Use(_))) => { + if place.as_local().is_some() { + // Writing to a local (e.g., a drop flag) does not + // turn a landing pad to a non-nop + } else { + return false; + } } StatementKind::Assign { .. } | diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 6edd28a4259a..aada7641df67 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -155,8 +155,8 @@ fn value_assigned_to_local<'a, 'tcx>( local: Local, ) -> Option<&'a mir::Rvalue<'tcx>> { if let mir::StatementKind::Assign(box (place, rvalue)) = &stmt.kind { - if let mir::Place { base: mir::PlaceBase::Local(l), projection: box [] } = place { - if local == *l { + if let Some(l) = place.as_local() { + if local == l { return Some(&*rvalue); } } @@ -192,7 +192,7 @@ impl PeekCall { tcx: TyCtxt<'tcx>, terminator: &mir::Terminator<'tcx>, ) -> Option { - use mir::{Operand, Place, PlaceBase}; + use mir::Operand; let span = terminator.source_info.span; if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } = @@ -207,14 +207,23 @@ impl PeekCall { assert_eq!(args.len(), 1); let kind = PeekCallKind::from_arg_ty(substs.type_at(0)); - let arg = match args[0] { - | Operand::Copy(Place { base: PlaceBase::Local(local), projection: box [] }) - | Operand::Move(Place { base: PlaceBase::Local(local), projection: box [] }) - => local, - + let arg = match &args[0] { + Operand::Copy(place) | Operand::Move(place) => { + if let Some(local) = place.as_local() { + local + } else { + tcx.sess.diagnostic().span_err( + span, + "dataflow::sanity_check cannot feed a non-temp to rustc_peek.", + ); + return None; + } + } _ => { tcx.sess.diagnostic().span_err( - span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek."); + span, + "dataflow::sanity_check cannot feed a non-temp to rustc_peek.", + ); return None; } }; @@ -277,12 +286,11 @@ impl<'tcx> RustcPeekAt<'tcx> for IndirectlyMutableLocals<'_, 'tcx> { call: PeekCall, ) { warn!("peek_at: place={:?}", place); - let local = match place { - mir::Place { base: mir::PlaceBase::Local(l), projection: box [] } => *l, - _ => { - tcx.sess.span_err(call.span, "rustc_peek: argument was not a local"); - return; - } + let local = if let Some(l) = place.as_local() { + l + } else { + tcx.sess.span_err(call.span, "rustc_peek: argument was not a local"); + return; }; if !flow_state.contains(local) { diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index efa39d91205b..07a7def3ea25 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -61,7 +61,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue { - if let box [proj_base @ .., elem] = &src_place.projection { + if let &[ref proj_base @ .., elem] = src_place.projection.as_ref() { if let ProjectionElem::ConstantIndex{offset: _, min_length: _, from_end: false} = elem { @@ -203,18 +203,17 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut { if let StatementKind::Assign(box(ref dst_place, ref rval)) = statement.kind { if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval { let items : Vec<_> = items.iter().map(|item| { - if let Operand::Move(Place { - base: PlaceBase::Local(local), - projection: box [], - }) = item { - let local_use = &visitor.locals_use[*local]; - let opt_index_and_place = - Self::try_get_item_source(local_use, body); - // each local should be used twice: - // in assign and in aggregate statements - if local_use.use_count == 2 && opt_index_and_place.is_some() { - let (index, src_place) = opt_index_and_place.unwrap(); - return Some((local_use, index, src_place)); + if let Operand::Move(place) = item { + if let Some(local) = place.as_local() { + let local_use = &visitor.locals_use[local]; + let opt_index_and_place = + Self::try_get_item_source(local_use, body); + // each local should be used twice: + // in assign and in aggregate statements + if local_use.use_count == 2 && opt_index_and_place.is_some() { + let (index, src_place) = opt_index_and_place.unwrap(); + return Some((local_use, index, src_place)); + } } } None @@ -293,33 +292,27 @@ impl RestoreSubsliceArrayMoveOut { if block.statements.len() > location.statement_index { let statement = &block.statements[location.statement_index]; if let StatementKind::Assign( - box( - Place { - base: PlaceBase::Local(_), - projection: box [], - }, - Rvalue::Use(Operand::Move(Place { - base: _, - projection: box [.., ProjectionElem::ConstantIndex { - offset, min_length: _, from_end: false - }], - })), - ) + box(place, Rvalue::Use(Operand::Move(src_place))) ) = &statement.kind { - // FIXME remove once we can use slices patterns - if let StatementKind::Assign( - box( - _, - Rvalue::Use(Operand::Move(Place { + if let (Some(_), PlaceRef { + base: _, + projection: &[.., ProjectionElem::ConstantIndex { + offset, min_length: _, from_end: false + }], + }) = (place.as_local(), src_place.as_ref()) { + if let StatementKind::Assign( + box(_, Rvalue::Use(Operand::Move(place))) + ) = &statement.kind { + if let PlaceRef { base, - projection: box [proj_base @ .., _], - })), - ) - ) = &statement.kind { - return Some((*offset, PlaceRef { - base, - projection: proj_base, - })) + projection: &[ref proj_base @ .., _], + } = place.as_ref() { + return Some((offset, PlaceRef { + base, + projection: proj_base, + })) + } + } } } } diff --git a/src/librustc_mir/util/alignment.rs b/src/librustc_mir/util/alignment.rs index 1bad85ec42d0..f949fcf0745f 100644 --- a/src/librustc_mir/util/alignment.rs +++ b/src/librustc_mir/util/alignment.rs @@ -38,8 +38,8 @@ fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<' where L: HasLocalDecls<'tcx>, { - let mut cursor = &*place.projection; - while let [proj_base @ .., elem] = cursor { + let mut cursor = place.projection.as_ref(); + while let &[ref proj_base @ .., elem] = cursor { cursor = proj_base; match elem {