]> git.lizzy.rs Git - rust.git/commitdiff
rustc_mir: implement visit_local instead/along visit_lvalue where possible.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Sun, 3 Sep 2017 16:14:31 +0000 (19:14 +0300)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Sun, 3 Sep 2017 16:14:31 +0000 (19:14 +0300)
src/librustc/mir/visit.rs
src/librustc_mir/transform/copy_prop.rs
src/librustc_mir/transform/generator.rs
src/librustc_mir/transform/inline.rs
src/librustc_mir/transform/promote_consts.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/simplify.rs
src/librustc_mir/util/def_use.rs
src/librustc_mir/util/liveness.rs
src/librustc_trans/mir/analyze.rs

index 6589e824187fd5b730c11b12166d249ef5aae044..6ee43953958009e11e6bb86547a6f64ce77c8744 100644 (file)
@@ -256,7 +256,9 @@ fn visit_local_decl(&mut self,
             }
 
             fn visit_local(&mut self,
-                                _local: & $($mutability)* Local) {
+                            _local: & $($mutability)* Local,
+                            _context: LvalueContext<'tcx>,
+                            _location: Location) {
             }
 
             fn visit_visibility_scope(&mut self,
@@ -610,7 +612,7 @@ fn super_lvalue(&mut self,
                             location: Location) {
                 match *lvalue {
                     Lvalue::Local(ref $($mutability)* local) => {
-                        self.visit_local(local);
+                        self.visit_local(local, context, location);
                     }
                     Lvalue::Static(ref $($mutability)* static_) => {
                         self.visit_static(static_, context, location);
index 186c465f6010585dfba38137541f1df31ceebf7b..ac8ebd306d321e844b2beda2cca17d3a7517ac33 100644 (file)
@@ -236,8 +236,7 @@ fn perform(self,
                 }
 
                 // Replace all uses of the destination local with the source local.
-                let src_lvalue = Lvalue::Local(src_local);
-                def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_lvalue);
+                def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_local);
 
                 // Finally, zap the now-useless assignment instruction.
                 debug!("  Deleting assignment");
index 9bc572c66b6f87c17897250617fe518f3d671720..8328bb9461eded2cb09d3a348f6fa20636ea08c2 100644 (file)
@@ -88,7 +88,9 @@ struct RenameLocalVisitor {
 
 impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
     fn visit_local(&mut self,
-                        local: &mut Local) {
+                   local: &mut Local,
+                   _: LvalueContext<'tcx>,
+                   _: Location) {
         if *local == self.from {
             *local = self.to;
         }
@@ -98,6 +100,13 @@ fn visit_local(&mut self,
 struct DerefArgVisitor;
 
 impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
+    fn visit_local(&mut self,
+                   local: &mut Local,
+                   _: LvalueContext<'tcx>,
+                   _: Location) {
+        assert_ne!(*local, self_arg());
+    }
+
     fn visit_lvalue(&mut self,
                     lvalue: &mut Lvalue<'tcx>,
                     context: LvalueContext<'tcx>,
@@ -177,6 +186,13 @@ fn set_state(&self, state_disc: u32, source_info: SourceInfo) -> Statement<'tcx>
 }
 
 impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
+    fn visit_local(&mut self,
+                   local: &mut Local,
+                   _: LvalueContext<'tcx>,
+                   _: Location) {
+        assert_eq!(self.remap.get(local), None);
+    }
+
     fn visit_lvalue(&mut self,
                     lvalue: &mut Lvalue<'tcx>,
                     context: LvalueContext<'tcx>,
index 124a1ef946e2bf85f9b876f9831ea7deb0718b01..3f8070fb3aa31929cb7b577060f64c9095978947 100644 (file)
@@ -589,16 +589,6 @@ fn update_target(&self, tgt: BasicBlock) -> BasicBlock {
         new
     }
 
-    fn update_local(&self, local: Local) -> Option<Local> {
-        let idx = local.index();
-        if idx < (self.args.len() + 1) {
-            return None;
-        }
-        let idx = idx - (self.args.len() + 1);
-        let local = Local::new(idx);
-        self.local_map.get(local).cloned()
-    }
-
     fn arg_index(&self, arg: Local) -> Option<usize> {
         let idx = arg.index();
         if idx > 0 && idx <= self.args.len() {
@@ -610,32 +600,35 @@ fn arg_index(&self, arg: Local) -> Option<usize> {
 }
 
 impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
+    fn visit_local(&mut self,
+                   local: &mut Local,
+                   _ctxt: LvalueContext<'tcx>,
+                   _location: Location) {
+        if *local == RETURN_POINTER {
+            match self.destination {
+                Lvalue::Local(l) => *local = l,
+                ref lval => bug!("Return lvalue is {:?}, not local", lval)
+            }
+        }
+        let idx = local.index() - 1;
+        if idx < self.args.len() {
+            match self.args[idx] {
+                Operand::Consume(Lvalue::Local(l)) => *local = l,
+                ref op => bug!("Arg operand `{:?}` is {:?}, not local", idx, op)
+            }
+        }
+        *local = self.local_map[Local::new(idx - self.args.len())];
+    }
+
     fn visit_lvalue(&mut self,
                     lvalue: &mut Lvalue<'tcx>,
                     _ctxt: LvalueContext<'tcx>,
                     _location: Location) {
-        if let Lvalue::Local(ref mut local) = *lvalue {
-            if let Some(l) = self.update_local(*local) {
-                // Temp or Var; update the local reference
-                *local = l;
-                return;
-            }
-        }
-        if let Lvalue::Local(local) = *lvalue {
-            if local == RETURN_POINTER {
-                // Return pointer; update the lvalue itself
-                *lvalue = self.destination.clone();
-            } else if local.index() < (self.args.len() + 1) {
-                // Argument, once again update the the lvalue itself
-                let idx = local.index() - 1;
-                if let Operand::Consume(ref lval) = self.args[idx] {
-                    *lvalue = lval.clone();
-                } else {
-                    bug!("Arg operand `{:?}` is not an Lvalue use.", idx)
-                }
-            }
+        if let Lvalue::Local(RETURN_POINTER) = *lvalue {
+            // Return pointer; update the lvalue itself
+            *lvalue = self.destination.clone();
         } else {
-            self.super_lvalue(lvalue, _ctxt, _location)
+            self.super_lvalue(lvalue, _ctxt, _location);
         }
     }
 
index 3e136fb9e9c49fc2a9c8f0c0c0394208b0d7c76b..53191806981a0a6b00958257deaa2f572beed131 100644 (file)
@@ -83,52 +83,49 @@ struct TempCollector<'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> {
-    fn visit_lvalue(&mut self,
-                    lvalue: &Lvalue<'tcx>,
-                    context: LvalueContext<'tcx>,
-                    location: Location) {
-        self.super_lvalue(lvalue, context, location);
-        if let Lvalue::Local(index) = *lvalue {
-            // We're only interested in temporaries
-            if self.mir.local_kind(index) != LocalKind::Temp {
-                return;
-            }
+    fn visit_local(&mut self,
+                   &index: &Local,
+                   context: LvalueContext<'tcx>,
+                   location: Location) {
+        // We're only interested in temporaries
+        if self.mir.local_kind(index) != LocalKind::Temp {
+            return;
+        }
 
-            // Ignore drops, if the temp gets promoted,
-            // then it's constant and thus drop is noop.
-            // Storage live ranges are also irrelevant.
-            if context.is_drop() || context.is_storage_marker() {
-                return;
-            }
+        // Ignore drops, if the temp gets promoted,
+        // then it's constant and thus drop is noop.
+        // Storage live ranges are also irrelevant.
+        if context.is_drop() || context.is_storage_marker() {
+            return;
+        }
 
-            let temp = &mut self.temps[index];
-            if *temp == TempState::Undefined {
-                match context {
-                    LvalueContext::Store |
-                    LvalueContext::Call => {
-                        *temp = TempState::Defined {
-                            location,
-                            uses: 0
-                        };
-                        return;
-                    }
-                    _ => { /* mark as unpromotable below */ }
-                }
-            } else if let TempState::Defined { ref mut uses, .. } = *temp {
-                // We always allow borrows, even mutable ones, as we need
-                // to promote mutable borrows of some ZSTs e.g. `&mut []`.
-                let allowed_use = match context {
-                    LvalueContext::Borrow {..} => true,
-                    _ => context.is_nonmutating_use()
-                };
-                if allowed_use {
-                    *uses += 1;
+        let temp = &mut self.temps[index];
+        if *temp == TempState::Undefined {
+            match context {
+                LvalueContext::Store |
+                LvalueContext::Call => {
+                    *temp = TempState::Defined {
+                        location,
+                        uses: 0
+                    };
                     return;
                 }
-                /* mark as unpromotable below */
+                _ => { /* mark as unpromotable below */ }
             }
-            *temp = TempState::Unpromotable;
+        } else if let TempState::Defined { ref mut uses, .. } = *temp {
+            // We always allow borrows, even mutable ones, as we need
+            // to promote mutable borrows of some ZSTs e.g. `&mut []`.
+            let allowed_use = match context {
+                LvalueContext::Borrow {..} => true,
+                _ => context.is_nonmutating_use()
+            };
+            if allowed_use {
+                *uses += 1;
+                return;
+            }
+            /* mark as unpromotable below */
         }
+        *temp = TempState::Unpromotable;
     }
 
     fn visit_source_info(&mut self, source_info: &SourceInfo) {
@@ -326,16 +323,13 @@ fn promote_candidate(mut self, candidate: Candidate) {
 
 /// Replaces all temporaries with their promoted counterparts.
 impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
-    fn visit_lvalue(&mut self,
-                    lvalue: &mut Lvalue<'tcx>,
-                    context: LvalueContext<'tcx>,
-                    location: Location) {
-        if let Lvalue::Local(ref mut temp) = *lvalue {
-            if self.source.local_kind(*temp) == LocalKind::Temp {
-                *temp = self.promote_temp(*temp);
-            }
+    fn visit_local(&mut self,
+                   local: &mut Local,
+                   _: LvalueContext<'tcx>,
+                   _: Location) {
+        if self.source.local_kind(*local) == LocalKind::Temp {
+            *local = self.promote_temp(*local);
         }
-        self.super_lvalue(lvalue, context, location);
     }
 }
 
index 9e64b0f9c77bebeb032807605baf86c2e60dbf1d..99e9f638a749b8175963c856f7d508ad3f191a95 100644 (file)
@@ -499,33 +499,40 @@ fn qualify_const(&mut self) -> (Qualif, Rc<IdxSetBuf<Local>>) {
 /// For functions (constant or not), it also records
 /// candidates for promotion in promotion_candidates.
 impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
+    fn visit_local(&mut self,
+                   &local: &Local,
+                   _: LvalueContext<'tcx>,
+                   _: Location) {
+        match self.mir.local_kind(local) {
+            LocalKind::ReturnPointer => {
+                self.not_const();
+            }
+            LocalKind::Arg => {
+                self.add(Qualif::FN_ARGUMENT);
+            }
+            LocalKind::Var => {
+                self.add(Qualif::NOT_CONST);
+            }
+            LocalKind::Temp => {
+                if !self.temp_promotion_state[local].is_promotable() {
+                    self.add(Qualif::NOT_PROMOTABLE);
+                }
+
+                if let Some(qualif) = self.temp_qualif[local] {
+                    self.add(qualif);
+                } else {
+                    self.not_const();
+                }
+            }
+        }
+    }
+
     fn visit_lvalue(&mut self,
                     lvalue: &Lvalue<'tcx>,
                     context: LvalueContext<'tcx>,
                     location: Location) {
         match *lvalue {
-            Lvalue::Local(local) => match self.mir.local_kind(local) {
-                LocalKind::ReturnPointer => {
-                    self.not_const();
-                }
-                LocalKind::Arg => {
-                    self.add(Qualif::FN_ARGUMENT);
-                }
-                LocalKind::Var => {
-                    self.add(Qualif::NOT_CONST);
-                }
-                LocalKind::Temp => {
-                    if !self.temp_promotion_state[local].is_promotable() {
-                        self.add(Qualif::NOT_PROMOTABLE);
-                    }
-
-                    if let Some(qualif) = self.temp_qualif[local] {
-                        self.add(qualif);
-                    } else {
-                        self.not_const();
-                    }
-                }
-            },
+            Lvalue::Local(ref local) => self.visit_local(local, context, location),
             Lvalue::Static(ref global) => {
                 self.add(Qualif::STATIC);
 
index 070250cda4d5d237358c4c422e3e202ca6fcd885..4b825e585aab9e97ff4db9adc770ffb14bdb9416 100644 (file)
@@ -352,15 +352,11 @@ struct DeclMarker {
 }
 
 impl<'tcx> Visitor<'tcx> for DeclMarker {
-    fn visit_lvalue(&mut self, lval: &Lvalue<'tcx>, ctx: LvalueContext<'tcx>, loc: Location) {
-        if ctx == LvalueContext::StorageLive || ctx == LvalueContext::StorageDead {
-            // ignore these altogether, they get removed along with their otherwise unused decls.
-            return;
+    fn visit_local(&mut self, local: &Local, ctx: LvalueContext<'tcx>, _: Location) {
+        // ignore these altogether, they get removed along with their otherwise unused decls.
+        if ctx != LvalueContext::StorageLive && ctx != LvalueContext::StorageDead {
+            self.locals.insert(local.index());
         }
-        if let Lvalue::Local(ref v) = *lval {
-            self.locals.insert(v.index());
-        }
-        self.super_lvalue(lval, ctx, loc);
     }
 }
 
@@ -384,11 +380,7 @@ fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockDat
         });
         self.super_basic_block_data(block, data);
     }
-    fn visit_lvalue(&mut self, lval: &mut Lvalue<'tcx>, ctx: LvalueContext<'tcx>, loc: Location) {
-        match *lval {
-            Lvalue::Local(ref mut l) => *l = Local::new(self.map[l.index()]),
-            _ => (),
-        };
-        self.super_lvalue(lval, ctx, loc);
+    fn visit_local(&mut self, l: &mut Local, _: LvalueContext<'tcx>, _: Location) {
+        *l = Local::new(self.map[l.index()]);
     }
 }
index 8263e149d84e74fa1b4e5c7459fd2158d10d4990..bd9fb4bc3cc5f6fd203c4372b3b5a31d1f170803 100644 (file)
@@ -10,7 +10,7 @@
 
 //! Def-use analysis.
 
-use rustc::mir::{Local, Location, Lvalue, Mir};
+use rustc::mir::{Local, Location, Mir};
 use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
 use rustc_data_structures::indexed_vec::IndexVec;
 use std::marker::PhantomData;
@@ -51,7 +51,7 @@ pub fn local_info(&self, local: Local) -> &Info<'tcx> {
     }
 
     fn mutate_defs_and_uses<F>(&self, local: Local, mir: &mut Mir<'tcx>, mut callback: F)
-                               where F: for<'a> FnMut(&'a mut Lvalue<'tcx>,
+                               where F: for<'a> FnMut(&'a mut Local,
                                                       LvalueContext<'tcx>,
                                                       Location) {
         for lvalue_use in &self.info[local].defs_and_uses {
@@ -65,8 +65,8 @@ fn mutate_defs_and_uses<F>(&self, local: Local, mir: &mut Mir<'tcx>, mut callbac
     pub fn replace_all_defs_and_uses_with(&self,
                                           local: Local,
                                           mir: &mut Mir<'tcx>,
-                                          new_lvalue: Lvalue<'tcx>) {
-        self.mutate_defs_and_uses(local, mir, |lvalue, _, _| *lvalue = new_lvalue.clone())
+                                          new_local: Local) {
+        self.mutate_defs_and_uses(local, mir, |local, _, _| *local = new_local)
     }
 }
 
@@ -74,30 +74,15 @@ struct DefUseFinder<'tcx> {
     info: IndexVec<Local, Info<'tcx>>,
 }
 
-impl<'tcx> DefUseFinder<'tcx> {
-    fn lvalue_mut_info(&mut self, lvalue: &Lvalue<'tcx>) -> Option<&mut Info<'tcx>> {
-        let info = &mut self.info;
-
-        if let Lvalue::Local(local) = *lvalue {
-            Some(&mut info[local])
-        } else {
-            None
-        }
-    }
-}
-
 impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> {
-    fn visit_lvalue(&mut self,
-                    lvalue: &Lvalue<'tcx>,
-                    context: LvalueContext<'tcx>,
-                    location: Location) {
-        if let Some(ref mut info) = self.lvalue_mut_info(lvalue) {
-            info.defs_and_uses.push(Use {
-                context,
-                location,
-            })
-        }
-        self.super_lvalue(lvalue, context, location)
+    fn visit_local(&mut self,
+                   &local: &Local,
+                   context: LvalueContext<'tcx>,
+                   location: Location) {
+        self.info[local].defs_and_uses.push(Use {
+            context,
+            location,
+        });
     }
 }
 
@@ -134,7 +119,7 @@ struct MutateUseVisitor<'tcx, F> {
 impl<'tcx, F> MutateUseVisitor<'tcx, F> {
     fn new(query: Local, callback: F, _: &Mir<'tcx>)
            -> MutateUseVisitor<'tcx, F>
-           where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) {
+           where F: for<'a> FnMut(&'a mut Local, LvalueContext<'tcx>, Location) {
         MutateUseVisitor {
             query,
             callback,
@@ -144,16 +129,13 @@ fn new(query: Local, callback: F, _: &Mir<'tcx>)
 }
 
 impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F>
-              where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) {
-    fn visit_lvalue(&mut self,
-                    lvalue: &mut Lvalue<'tcx>,
+              where F: for<'a> FnMut(&'a mut Local, LvalueContext<'tcx>, Location) {
+    fn visit_local(&mut self,
+                    local: &mut Local,
                     context: LvalueContext<'tcx>,
                     location: Location) {
-        if let Lvalue::Local(local) = *lvalue {
-            if local == self.query {
-                (self.callback)(lvalue, context, location)
-            }
+        if *local == self.query {
+            (self.callback)(local, context, location)
         }
-        self.super_lvalue(lvalue, context, location)
     }
 }
index fd15c90dc901360ab6c684f2770b014e08bd8062..e6d3a82ff9b5306509fb8fa6593b38531104ec5d 100644 (file)
@@ -60,49 +60,45 @@ struct BlockInfoVisitor {
 }
 
 impl<'tcx> Visitor<'tcx> for BlockInfoVisitor {
-    fn visit_lvalue(&mut self,
-                    lvalue: &Lvalue<'tcx>,
-                    context: LvalueContext<'tcx>,
-                    location: Location) {
-        if let Lvalue::Local(local) = *lvalue {
-            match context {
-                LvalueContext::Store |
-
-                // We let Call defined the result in both the success and unwind cases.
-                // This may not be right.
-                LvalueContext::Call |
-
-                // Storage live and storage dead aren't proper defines, but we can ignore
-                // values that come before them.
-                LvalueContext::StorageLive |
-                LvalueContext::StorageDead => {
-                    self.defs.add(&local);
-                }
-                LvalueContext::Projection(..) |
-
-                // Borrows only consider their local used at the point of the borrow.
-                // This won't affect the results since we use this analysis for generators
-                // and we only care about the result at suspension points. Borrows cannot
-                // cross suspension points so this behavior is unproblematic.
-                LvalueContext::Borrow { .. } |
-
-                LvalueContext::Inspect |
-                LvalueContext::Consume |
-                LvalueContext::Validate |
-
-                // We consider drops to always be uses of locals.
-                // Drop eloboration should be run before this analysis otherwise
-                // the results might be too pessimistic.
-                LvalueContext::Drop => {
-                    // Ignore uses which are already defined in this block
-                    if !self.pre_defs.contains(&local) {
-                        self.uses.add(&local);
-                    }
+    fn visit_local(&mut self,
+                   &local: &Local,
+                   context: LvalueContext<'tcx>,
+                   _: Location) {
+        match context {
+            LvalueContext::Store |
+
+            // We let Call defined the result in both the success and unwind cases.
+            // This may not be right.
+            LvalueContext::Call |
+
+            // Storage live and storage dead aren't proper defines, but we can ignore
+            // values that come before them.
+            LvalueContext::StorageLive |
+            LvalueContext::StorageDead => {
+                self.defs.add(&local);
+            }
+            LvalueContext::Projection(..) |
+
+            // Borrows only consider their local used at the point of the borrow.
+            // This won't affect the results since we use this analysis for generators
+            // and we only care about the result at suspension points. Borrows cannot
+            // cross suspension points so this behavior is unproblematic.
+            LvalueContext::Borrow { .. } |
+
+            LvalueContext::Inspect |
+            LvalueContext::Consume |
+            LvalueContext::Validate |
+
+            // We consider drops to always be uses of locals.
+            // Drop eloboration should be run before this analysis otherwise
+            // the results might be too pessimistic.
+            LvalueContext::Drop => {
+                // Ignore uses which are already defined in this block
+                if !self.pre_defs.contains(&local) {
+                    self.uses.add(&local);
                 }
             }
         }
-
-        self.super_lvalue(lvalue, context, location)
     }
 }
 
index a17ddabb1a7cdade098131471633a1e615b865bd..95b76d32bf8484d450b040c15421cd6fb45f1200 100644 (file)
@@ -134,60 +134,61 @@ fn visit_lvalue(&mut self,
                     location: Location) {
         debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context);
 
-        // Allow uses of projections of immediate pair fields.
         if let mir::Lvalue::Projection(ref proj) = *lvalue {
-            if let mir::Lvalue::Local(_) = proj.base {
-                let ty = proj.base.ty(self.cx.mir, self.cx.ccx.tcx());
-
-                let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
-                if common::type_is_imm_pair(self.cx.ccx, ty) {
+            // Allow uses of projections of immediate pair fields.
+            if let LvalueContext::Consume = context {
+                if let mir::Lvalue::Local(_) = proj.base {
                     if let mir::ProjectionElem::Field(..) = proj.elem {
-                        if let LvalueContext::Consume = context {
+                        let ty = proj.base.ty(self.cx.mir, self.cx.ccx.tcx());
+
+                        let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
+                        if common::type_is_imm_pair(self.cx.ccx, ty) {
                             return;
                         }
                     }
                 }
             }
-        }
 
-        if let mir::Lvalue::Local(index) = *lvalue {
-            match context {
-                LvalueContext::Call => {
-                    self.mark_assigned(index);
-                }
+            // A deref projection only reads the pointer, never needs the lvalue.
+            if let mir::ProjectionElem::Deref = proj.elem {
+                return self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
+            }
+        }
 
-                LvalueContext::StorageLive |
-                LvalueContext::StorageDead |
-                LvalueContext::Validate |
-                LvalueContext::Inspect |
-                LvalueContext::Consume => {}
+        self.super_lvalue(lvalue, context, location);
+    }
 
-                LvalueContext::Store |
-                LvalueContext::Borrow { .. } |
-                LvalueContext::Projection(..) => {
-                    self.mark_as_lvalue(index);
-                }
+    fn visit_local(&mut self,
+                   &index: &mir::Local,
+                   context: LvalueContext<'tcx>,
+                   _: Location) {
+        match context {
+            LvalueContext::Call => {
+                self.mark_assigned(index);
+            }
 
-                LvalueContext::Drop => {
-                    let ty = lvalue.ty(self.cx.mir, self.cx.ccx.tcx());
-                    let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
+            LvalueContext::StorageLive |
+            LvalueContext::StorageDead |
+            LvalueContext::Validate |
+            LvalueContext::Inspect |
+            LvalueContext::Consume => {}
 
-                    // Only need the lvalue if we're actually dropping it.
-                    if self.cx.ccx.shared().type_needs_drop(ty) {
-                        self.mark_as_lvalue(index);
-                    }
-                }
+            LvalueContext::Store |
+            LvalueContext::Borrow { .. } |
+            LvalueContext::Projection(..) => {
+                self.mark_as_lvalue(index);
             }
-        }
 
-        // A deref projection only reads the pointer, never needs the lvalue.
-        if let mir::Lvalue::Projection(ref proj) = *lvalue {
-            if let mir::ProjectionElem::Deref = proj.elem {
-                return self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
+            LvalueContext::Drop => {
+                let ty = mir::Lvalue::Local(index).ty(self.cx.mir, self.cx.ccx.tcx());
+                let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
+
+                // Only need the lvalue if we're actually dropping it.
+                if self.cx.ccx.shared().type_needs_drop(ty) {
+                    self.mark_as_lvalue(index);
+                }
             }
         }
-
-        self.super_lvalue(lvalue, context, location);
     }
 }