diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index bb6a13ed15a..549608bf7ee 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -154,51 +154,62 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> context: PlaceContext, location: Location) { debug!("visit_place(place={:?}, context={:?})", place, context); + let mut context = context; let cx = self.fx.cx; - if let mir::Place::Projection(ref proj) = *place { - // Allow uses of projections that are ZSTs or from scalar fields. - let is_consume = match context { - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => true, - _ => false - }; - if is_consume { - let base_ty = proj.base.ty(self.fx.mir, cx.tcx()); - let base_ty = self.fx.monomorphize(&base_ty); + place.iterate(|place_base, place_projections| { + for proj in place_projections { + // Allow uses of projections that are ZSTs or from scalar fields. + let is_consume = match context { + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => true, + _ => false + }; + if is_consume { + let base_ty = proj.base.ty(self.fx.mir, cx.tcx()); + let base_ty = self.fx.monomorphize(&base_ty); - // ZSTs don't require any actual memory access. - let elem_ty = base_ty - .projection_ty(cx.tcx(), &proj.elem) - .ty; - let elem_ty = self.fx.monomorphize(&elem_ty); - if cx.layout_of(elem_ty).is_zst() { - return; - } - - if let mir::ProjectionElem::Field(..) = proj.elem { - let layout = cx.layout_of(base_ty.ty); - if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) { - // Recurse with the same context, instead of `Projection`, - // potentially stopping at non-operand projections, - // which would trigger `not_ssa` on locals. - self.visit_place(&proj.base, context, location); + // ZSTs don't require any actual memory access. + let elem_ty = base_ty + .projection_ty(cx.tcx(), &proj.elem) + .ty; + let elem_ty = self.fx.monomorphize(&elem_ty); + if cx.layout_of(elem_ty).is_zst() { return; } + + if let mir::ProjectionElem::Field(..) = proj.elem { + let layout = cx.layout_of(base_ty.ty); + if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) { + // Recurse with the same context, instead of `Projection`, + // potentially stopping at non-operand projections, + // which would trigger `not_ssa` on locals. + continue; + } + } } + + // A deref projection only reads the pointer, never needs the place. + if let mir::ProjectionElem::Deref = proj.elem { + return self.visit_place( + &proj.base, + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), + location + ); + } + + context = if context.is_mutating_use() { + PlaceContext::MutatingUse(MutatingUseContext::Projection) + } else { + PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) + }; } - // A deref projection only reads the pointer, never needs the place. - if let mir::ProjectionElem::Deref = proj.elem { - return self.visit_place( - &proj.base, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), - location - ); + // Default base visit behavior + if let mir::PlaceBase::Local(local) = place_base { + self.visit_local(local, context, location); } - } - - self.super_place(place, context, location); + }); } fn visit_local(&mut self,