about summary refs log tree commit diff
path: root/src/librustc_codegen_ssa
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc_codegen_ssa')
-rw-r--r--src/librustc_codegen_ssa/mir/analyze.rs85
1 files changed, 48 insertions, 37 deletions
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);
-
-                // 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);
+        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.
+                            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
-                );
+                // 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)
+                };
             }
-        }
 
-        self.super_place(place, context, location);
+            // Default base visit behavior
+            if let mir::PlaceBase::Local(local) = place_base {
+                self.visit_local(local, context, location);
+            }
+        });
     }
 
     fn visit_local(&mut self,