about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-09-08 19:57:14 +0000
committerbors <bors@rust-lang.org>2018-09-08 19:57:14 +0000
commit0198a1ea45e29af00d92423aa6d2ac876410c3f9 (patch)
tree2711480bf2a79b00b1ba712f42dd01e9bc52b04a
parent968d95e9402e69c6a63b6b0a80da0de8307e0fcc (diff)
parentd0c1e5a99e3a9b0d57e8f1deea3c76bd1fb7c0e9 (diff)
downloadrust-0198a1ea45e29af00d92423aa6d2ac876410c3f9.tar.gz
rust-0198a1ea45e29af00d92423aa6d2ac876410c3f9.zip
Auto merge of #53909 - mikhail-m1:53643, r=nikomatsakis
Skip a shared borrow of a immutable local variables

issue #53643

r? @nikomatsakis
-rw-r--r--src/librustc/mir/mod.rs38
-rw-r--r--src/librustc_mir/borrow_check/borrow_set.rs60
-rw-r--r--src/librustc_mir/borrow_check/mod.rs12
-rw-r--r--src/librustc_mir/borrow_check/place_ext.rs45
-rw-r--r--src/librustc_mir/build/expr/as_constant.rs32
-rw-r--r--src/librustc_mir/build/expr/as_operand.rs50
-rw-r--r--src/librustc_mir/build/expr/as_place.rs173
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs362
-rw-r--r--src/librustc_mir/build/expr/as_temp.rs68
-rw-r--r--src/librustc_mir/build/expr/category.rs84
-rw-r--r--src/librustc_mir/build/expr/into.rs249
-rw-r--r--src/librustc_mir/build/expr/mod.rs2
-rw-r--r--src/librustc_mir/build/expr/stmt.rs90
-rw-r--r--src/librustc_mir/dataflow/impls/borrows.rs10
-rw-r--r--src/librustc_mir/dataflow/move_paths/mod.rs10
-rw-r--r--src/librustc_mir/util/pretty.rs3
-rw-r--r--src/test/mir-opt/end_region_destruction_extents_1.rs8
-rw-r--r--src/test/mir-opt/storage_live_dead_in_statics.rs4
18 files changed, 822 insertions, 478 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index c6a1281061f..708ce8e2031 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -249,11 +249,6 @@ impl<'tcx> Mir<'tcx> {
         } else if self.local_decls[local].name.is_some() {
             LocalKind::Var
         } else {
-            debug_assert!(
-                self.local_decls[local].mutability == Mutability::Mut,
-                "temp should be mutable"
-            );
-
             LocalKind::Temp
         }
     }
@@ -782,25 +777,30 @@ impl<'tcx> LocalDecl<'tcx> {
     /// Create a new `LocalDecl` for a temporary.
     #[inline]
     pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self {
-        LocalDecl {
-            mutability: Mutability::Mut,
-            ty,
-            name: None,
-            source_info: SourceInfo {
-                span,
-                scope: OUTERMOST_SOURCE_SCOPE,
-            },
-            visibility_scope: OUTERMOST_SOURCE_SCOPE,
-            internal: false,
-            is_user_variable: None,
-        }
+        Self::new_local(ty, Mutability::Mut, false, span)
+    }
+
+    /// Create a new immutable `LocalDecl` for a temporary.
+    #[inline]
+    pub fn new_immutable_temp(ty: Ty<'tcx>, span: Span) -> Self {
+        Self::new_local(ty, Mutability::Not, false, span)
     }
 
     /// Create a new `LocalDecl` for a internal temporary.
     #[inline]
     pub fn new_internal(ty: Ty<'tcx>, span: Span) -> Self {
+        Self::new_local(ty, Mutability::Mut, true, span)
+    }
+
+    #[inline]
+    fn new_local(
+        ty: Ty<'tcx>,
+        mutability: Mutability,
+        internal: bool,
+        span: Span,
+    ) -> Self {
         LocalDecl {
-            mutability: Mutability::Mut,
+            mutability,
             ty,
             name: None,
             source_info: SourceInfo {
@@ -808,7 +808,7 @@ impl<'tcx> LocalDecl<'tcx> {
                 scope: OUTERMOST_SOURCE_SCOPE,
             },
             visibility_scope: OUTERMOST_SOURCE_SCOPE,
-            internal: true,
+            internal,
             is_user_variable: None,
         }
     }
diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs
index 454f89e5d06..8ddcfa05432 100644
--- a/src/librustc_mir/borrow_check/borrow_set.rs
+++ b/src/librustc_mir/borrow_check/borrow_set.rs
@@ -10,12 +10,14 @@
 
 use borrow_check::place_ext::PlaceExt;
 use dataflow::indexes::BorrowIndex;
+use dataflow::move_paths::MoveData;
 use rustc::mir::traversal;
 use rustc::mir::visit::{PlaceContext, Visitor};
-use rustc::mir::{self, Location, Mir, Place};
+use rustc::mir::{self, Location, Mir, Place, Local};
 use rustc::ty::{Region, TyCtxt};
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_data_structures::bitvec::BitArray;
 use std::fmt;
 use std::hash::Hash;
 use std::ops::Index;
@@ -43,6 +45,8 @@ crate struct BorrowSet<'tcx> {
 
     /// Map from local to all the borrows on that local
     crate local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
+
+    crate locals_state_at_exit: LocalsStateAtExit,
 }
 
 impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
@@ -96,8 +100,52 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
     }
 }
 
+crate enum LocalsStateAtExit {
+    AllAreInvalidated,
+    SomeAreInvalidated { has_storage_dead_or_moved: BitArray<Local> }
+}
+
+impl LocalsStateAtExit {
+    fn build(
+        locals_are_invalidated_at_exit: bool,
+        mir: &Mir<'tcx>,
+        move_data: &MoveData<'tcx>
+    ) -> Self {
+        struct HasStorageDead(BitArray<Local>);
+
+        impl<'tcx> Visitor<'tcx> for HasStorageDead {
+            fn visit_local(&mut self, local: &Local, ctx: PlaceContext<'tcx>, _: Location) {
+                if ctx == PlaceContext::StorageDead {
+                    self.0.insert(*local);
+                }
+            }
+        }
+
+        if locals_are_invalidated_at_exit {
+            LocalsStateAtExit::AllAreInvalidated
+        } else {
+            let mut has_storage_dead = HasStorageDead(BitArray::new(mir.local_decls.len()));
+            has_storage_dead.visit_mir(mir);
+            let mut has_storage_dead_or_moved = has_storage_dead.0;
+            for move_out in &move_data.moves {
+                if let Some(index) = move_data.base_local(move_out.path) {
+                    has_storage_dead_or_moved.insert(index);
+
+                }
+            }
+            LocalsStateAtExit::SomeAreInvalidated{ has_storage_dead_or_moved }
+        }
+    }
+}
+
 impl<'tcx> BorrowSet<'tcx> {
-    pub fn build(tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> Self {
+    pub fn build(
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        mir: &Mir<'tcx>,
+        locals_are_invalidated_at_exit: bool,
+        move_data: &MoveData<'tcx>
+    ) -> Self {
+
         let mut visitor = GatherBorrows {
             tcx,
             mir,
@@ -107,6 +155,8 @@ impl<'tcx> BorrowSet<'tcx> {
             region_map: FxHashMap(),
             local_map: FxHashMap(),
             pending_activations: FxHashMap(),
+            locals_state_at_exit:
+                LocalsStateAtExit::build(locals_are_invalidated_at_exit, mir, move_data),
         };
 
         for (block, block_data) in traversal::preorder(mir) {
@@ -119,6 +169,7 @@ impl<'tcx> BorrowSet<'tcx> {
             activation_map: visitor.activation_map,
             region_map: visitor.region_map,
             local_map: visitor.local_map,
+            locals_state_at_exit: visitor.locals_state_at_exit,
         }
     }
 
@@ -148,6 +199,8 @@ struct GatherBorrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
     /// the borrow. When we find a later use of this activation, we
     /// remove from the map (and add to the "tombstone" set below).
     pending_activations: FxHashMap<mir::Local, BorrowIndex>,
+
+    locals_state_at_exit: LocalsStateAtExit,
 }
 
 impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
@@ -159,7 +212,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
         location: mir::Location,
     ) {
         if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue {
-            if borrowed_place.ignore_borrow(self.tcx, self.mir) {
+            if borrowed_place.ignore_borrow(
+                self.tcx, self.mir, &self.locals_state_at_exit) {
                 return;
             }
 
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 5050b5ab2b4..76f6bcb5e56 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -196,7 +196,12 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         |bd, i| DebugFormatted::new(&bd.move_data().inits[i]),
     ));
 
-    let borrow_set = Rc::new(BorrowSet::build(tcx, mir));
+    let locals_are_invalidated_at_exit = match tcx.hir.body_owner_kind(id) {
+            hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => false,
+            hir::BodyOwnerKind::Fn => true,
+    };
+    let borrow_set = Rc::new(BorrowSet::build(
+            tcx, mir, locals_are_invalidated_at_exit, &mdpe.move_data));
 
     // If we are in non-lexical mode, compute the non-lexical lifetimes.
     let (regioncx, polonius_output, opt_closure_req) = nll::compute_regions(
@@ -241,10 +246,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         param_env: param_env,
         location_table,
         movable_generator,
-        locals_are_invalidated_at_exit: match tcx.hir.body_owner_kind(id) {
-            hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => false,
-            hir::BodyOwnerKind::Fn => true,
-        },
+        locals_are_invalidated_at_exit,
         access_place_error_reported: FxHashSet(),
         reservation_error_reported: FxHashSet(),
         moved_error_reported: FxHashSet(),
diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs
index 2b4a1553e1a..740cc645984 100644
--- a/src/librustc_mir/borrow_check/place_ext.rs
+++ b/src/librustc_mir/borrow_check/place_ext.rs
@@ -10,8 +10,9 @@
 
 use rustc::hir;
 use rustc::mir::ProjectionElem;
-use rustc::mir::{Local, Mir, Place};
+use rustc::mir::{Local, Mir, Place, Mutability};
 use rustc::ty::{self, TyCtxt};
+use borrow_check::borrow_set::LocalsStateAtExit;
 
 /// Extension methods for the `Place` type.
 crate trait PlaceExt<'tcx> {
@@ -19,7 +20,12 @@ crate trait PlaceExt<'tcx> {
     /// This is true whenever there is no action that the user can do
     /// to the place `self` that would invalidate the borrow. This is true
     /// for borrows of raw pointer dereferents as well as shared references.
-    fn ignore_borrow(&self, tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> bool;
+    fn ignore_borrow(
+        &self,
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        mir: &Mir<'tcx>,
+        locals_state_at_exit: &LocalsStateAtExit,
+        ) -> bool;
 
     /// If this is a place like `x.f.g`, returns the local
     /// `x`. Returns `None` if this is based in a static.
@@ -27,10 +33,34 @@ crate trait PlaceExt<'tcx> {
 }
 
 impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
-    fn ignore_borrow(&self, tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> bool {
+    fn ignore_borrow(
+        &self,
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        mir: &Mir<'tcx>,
+        locals_state_at_exit: &LocalsStateAtExit,
+    ) -> bool {
         match self {
-            Place::Promoted(_) |
-            Place::Local(_) => false,
+            Place::Promoted(_) => false,
+
+            // If a local variable is immutable, then we only need to track borrows to guard
+            // against two kinds of errors:
+            // * The variable being dropped while still borrowed (e.g., because the fn returns
+            //   a reference to a local variable)
+            // * The variable being moved while still borrowed
+            //
+            // In particular, the variable cannot be mutated -- the "access checks" will fail --
+            // so we don't have to worry about mutation while borrowed.
+            Place::Local(index) => {
+                match locals_state_at_exit {
+                    LocalsStateAtExit::AllAreInvalidated => false,
+                    LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
+                        let ignore = !has_storage_dead_or_moved.contains(*index) &&
+                            mir.local_decls[*index].mutability == Mutability::Not;
+                        debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
+                        ignore
+                    }
+                }
+            }
             Place::Static(static_) => {
                 tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable)
             }
@@ -39,7 +69,8 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
                 | ProjectionElem::Downcast(..)
                 | ProjectionElem::Subslice { .. }
                 | ProjectionElem::ConstantIndex { .. }
-                | ProjectionElem::Index(_) => proj.base.ignore_borrow(tcx, mir),
+                | ProjectionElem::Index(_) => proj.base.ignore_borrow(
+                    tcx, mir, locals_state_at_exit),
 
                 ProjectionElem::Deref => {
                     let ty = proj.base.ty(mir, tcx).to_ty(tcx);
@@ -55,7 +86,7 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
                         // borrowed *that* one, leaving the original
                         // path unborrowed.
                         ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => true,
-                        _ => proj.base.ignore_borrow(tcx, mir),
+                        _ => proj.base.ignore_borrow(tcx, mir, locals_state_at_exit),
                     }
                 }
             },
diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs
index 1106f750d6d..606bd2978b6 100644
--- a/src/librustc_mir/build/expr/as_constant.rs
+++ b/src/librustc_mir/build/expr/as_constant.rs
@@ -18,7 +18,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Compile `expr`, yielding a compile-time constant. Assumes that
     /// `expr` is a valid compile-time constant!
     pub fn as_constant<M>(&mut self, expr: M) -> Constant<'tcx>
-        where M: Mirror<'tcx, Output=Expr<'tcx>>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
     {
         let expr = self.hir.mirror(expr);
         self.expr_as_constant(expr)
@@ -26,18 +27,25 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     fn expr_as_constant(&mut self, expr: Expr<'tcx>) -> Constant<'tcx> {
         let this = self;
-        let Expr { ty, temp_lifetime: _, span, kind }
-            = expr;
+        let Expr {
+            ty,
+            temp_lifetime: _,
+            span,
+            kind,
+        } = expr;
         match kind {
-            ExprKind::Scope { region_scope: _, lint_level: _, value } =>
-                this.as_constant(value),
-            ExprKind::Literal { literal, user_ty } =>
-                Constant { span, ty, user_ty, literal },
-            _ =>
-                span_bug!(
-                    span,
-                    "expression is not a valid constant {:?}",
-                    kind),
+            ExprKind::Scope {
+                region_scope: _,
+                lint_level: _,
+                value,
+            } => this.as_constant(value),
+            ExprKind::Literal { literal, user_ty } => Constant {
+                span,
+                ty,
+                user_ty,
+                literal,
+            },
+            _ => span_bug!(span, "expression is not a valid constant {:?}", kind),
         }
     }
 }
diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs
index 7eae414a391..8046d898e0a 100644
--- a/src/librustc_mir/build/expr/as_operand.rs
+++ b/src/librustc_mir/build/expr/as_operand.rs
@@ -10,8 +10,8 @@
 
 //! See docs in build/expr/mod.rs
 
-use build::{BlockAnd, BlockAndExtension, Builder};
 use build::expr::category::Category;
+use build::{BlockAnd, BlockAndExtension, Builder};
 use hair::*;
 use rustc::middle::region;
 use rustc::mir::*;
@@ -23,9 +23,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// The operand returned from this function will *not be valid* after
     /// an ExprKind::Scope is passed, so please do *not* return it from
     /// functions to avoid bad miscompiles.
-    pub fn as_local_operand<M>(&mut self, block: BasicBlock, expr: M)
-                             -> BlockAnd<Operand<'tcx>>
-        where M: Mirror<'tcx, Output = Expr<'tcx>>
+    pub fn as_local_operand<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Operand<'tcx>>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
     {
         let local_scope = self.local_scope();
         self.as_operand(block, local_scope, expr)
@@ -37,25 +37,34 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// this time.
     ///
     /// The operand is known to be live until the end of `scope`.
-    pub fn as_operand<M>(&mut self,
-                         block: BasicBlock,
-                         scope: Option<region::Scope>,
-                         expr: M) -> BlockAnd<Operand<'tcx>>
-        where M: Mirror<'tcx, Output = Expr<'tcx>>
+    pub fn as_operand<M>(
+        &mut self,
+        block: BasicBlock,
+        scope: Option<region::Scope>,
+        expr: M,
+    ) -> BlockAnd<Operand<'tcx>>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
     {
         let expr = self.hir.mirror(expr);
         self.expr_as_operand(block, scope, expr)
     }
 
-    fn expr_as_operand(&mut self,
-                       mut block: BasicBlock,
-                       scope: Option<region::Scope>,
-                       expr: Expr<'tcx>)
-                       -> BlockAnd<Operand<'tcx>> {
+    fn expr_as_operand(
+        &mut self,
+        mut block: BasicBlock,
+        scope: Option<region::Scope>,
+        expr: Expr<'tcx>,
+    ) -> BlockAnd<Operand<'tcx>> {
         debug!("expr_as_operand(block={:?}, expr={:?})", block, expr);
         let this = self;
 
-        if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
+        if let ExprKind::Scope {
+            region_scope,
+            lint_level,
+            value,
+        } = expr.kind
+        {
             let source_info = this.source_info(expr.span);
             let region_scope = (region_scope, source_info);
             return this.in_scope(region_scope, lint_level, block, |this| {
@@ -64,16 +73,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         }
 
         let category = Category::of(&expr.kind).unwrap();
-        debug!("expr_as_operand: category={:?} for={:?}", category, expr.kind);
+        debug!(
+            "expr_as_operand: category={:?} for={:?}",
+            category, expr.kind
+        );
         match category {
             Category::Constant => {
                 let constant = this.as_constant(expr);
                 block.and(Operand::Constant(box constant))
             }
-            Category::Place |
-            Category::Rvalue(..) => {
-                let operand =
-                    unpack!(block = this.as_temp(block, scope, expr));
+            Category::Place | Category::Rvalue(..) => {
+                let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut));
                 block.and(Operand::Move(Place::Local(operand)))
             }
         }
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index a38ca7ae5bf..5688ea9d260 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -10,42 +10,64 @@
 
 //! See docs in build/expr/mod.rs
 
-use build::{BlockAnd, BlockAndExtension, Builder};
-use build::ForGuard::{OutsideGuard, RefWithinGuard};
 use build::expr::category::Category;
+use build::ForGuard::{OutsideGuard, RefWithinGuard};
+use build::{BlockAnd, BlockAndExtension, Builder};
 use hair::*;
-use rustc::mir::*;
 use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
+use rustc::mir::*;
 
 use rustc_data_structures::indexed_vec::Idx;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Compile `expr`, yielding a place that we can move from etc.
-    pub fn as_place<M>(&mut self,
-                        block: BasicBlock,
-                        expr: M)
-                        -> BlockAnd<Place<'tcx>>
-        where M: Mirror<'tcx, Output=Expr<'tcx>>
+    pub fn as_place<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
     {
         let expr = self.hir.mirror(expr);
-        self.expr_as_place(block, expr)
+        self.expr_as_place(block, expr, Mutability::Mut)
     }
 
-    fn expr_as_place(&mut self,
-                      mut block: BasicBlock,
-                      expr: Expr<'tcx>)
-                      -> BlockAnd<Place<'tcx>> {
-        debug!("expr_as_place(block={:?}, expr={:?})", block, expr);
+    /// Compile `expr`, yielding a place that we can move from etc.
+    /// Mutability note: The caller of this method promises only to read from the resulting
+    /// place. The place itself may or may not be mutable:
+    /// * If this expr is a place expr like a.b, then we will return that place.
+    /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
+    pub fn as_read_only_place<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
+    {
+        let expr = self.hir.mirror(expr);
+        self.expr_as_place(block, expr, Mutability::Not)
+    }
+
+    fn expr_as_place(
+        &mut self,
+        mut block: BasicBlock,
+        expr: Expr<'tcx>,
+        mutability: Mutability,
+    ) -> BlockAnd<Place<'tcx>> {
+        debug!(
+            "expr_as_place(block={:?}, expr={:?}, mutability={:?})",
+            block, expr, mutability
+        );
 
         let this = self;
         let expr_span = expr.span;
         let source_info = this.source_info(expr_span);
         match expr.kind {
-            ExprKind::Scope { region_scope, lint_level, value } => {
-                this.in_scope((region_scope, source_info), lint_level, block, |this| {
+            ExprKind::Scope {
+                region_scope,
+                lint_level,
+                value,
+            } => this.in_scope((region_scope, source_info), lint_level, block, |this| {
+                if mutability == Mutability::Not {
+                    this.as_read_only_place(block, value)
+                } else {
                     this.as_place(block, value)
-                })
-            }
+                }
+            }),
             ExprKind::Field { lhs, name } => {
                 let place = unpack!(block = this.as_place(block, lhs));
                 let place = place.field(name, expr.ty);
@@ -63,32 +85,43 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // region_scope=None so place indexes live forever. They are scalars so they
                 // do not need storage annotations, and they are often copied between
                 // places.
-                let idx = unpack!(block = this.as_temp(block, None, index));
+                let idx = unpack!(block = this.as_temp(block, None, index, Mutability::Mut));
 
                 // bounds check:
-                let (len, lt) = (this.temp(usize_ty.clone(), expr_span),
-                                 this.temp(bool_ty, expr_span));
-                this.cfg.push_assign(block, source_info, // len = len(slice)
-                                     &len, Rvalue::Len(slice.clone()));
-                this.cfg.push_assign(block, source_info, // lt = idx < len
-                                     &lt, Rvalue::BinaryOp(BinOp::Lt,
-                                                           Operand::Copy(Place::Local(idx)),
-                                                           Operand::Copy(len.clone())));
+                let (len, lt) = (
+                    this.temp(usize_ty.clone(), expr_span),
+                    this.temp(bool_ty, expr_span),
+                );
+                this.cfg.push_assign(
+                    block,
+                    source_info, // len = len(slice)
+                    &len,
+                    Rvalue::Len(slice.clone()),
+                );
+                this.cfg.push_assign(
+                    block,
+                    source_info, // lt = idx < len
+                    &lt,
+                    Rvalue::BinaryOp(
+                        BinOp::Lt,
+                        Operand::Copy(Place::Local(idx)),
+                        Operand::Copy(len.clone()),
+                    ),
+                );
 
                 let msg = BoundsCheck {
                     len: Operand::Move(len),
-                    index: Operand::Copy(Place::Local(idx))
+                    index: Operand::Copy(Place::Local(idx)),
                 };
-                let success = this.assert(block, Operand::Move(lt), true,
-                                          msg, expr_span);
+                let success = this.assert(block, Operand::Move(lt), true, msg, expr_span);
                 success.and(slice.index(idx))
             }
-            ExprKind::SelfRef => {
-                block.and(Place::Local(Local::new(1)))
-            }
+            ExprKind::SelfRef => block.and(Place::Local(Local::new(1))),
             ExprKind::VarRef { id } => {
-                let place = if this.is_bound_var_in_guard(id) &&
-                    this.hir.tcx().all_pat_vars_are_implicit_refs_within_guards()
+                let place = if this.is_bound_var_in_guard(id) && this
+                    .hir
+                    .tcx()
+                    .all_pat_vars_are_implicit_refs_within_guards()
                 {
                     let index = this.var_local_id(id, RefWithinGuard);
                     Place::Local(index).deref()
@@ -98,46 +131,48 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 };
                 block.and(place)
             }
-            ExprKind::StaticRef { id } => {
-                block.and(Place::Static(Box::new(Static { def_id: id, ty: expr.ty })))
-            }
+            ExprKind::StaticRef { id } => block.and(Place::Static(Box::new(Static {
+                def_id: id,
+                ty: expr.ty,
+            }))),
 
-            ExprKind::Array { .. } |
-            ExprKind::Tuple { .. } |
-            ExprKind::Adt { .. } |
-            ExprKind::Closure { .. } |
-            ExprKind::Unary { .. } |
-            ExprKind::Binary { .. } |
-            ExprKind::LogicalOp { .. } |
-            ExprKind::Box { .. } |
-            ExprKind::Cast { .. } |
-            ExprKind::Use { .. } |
-            ExprKind::NeverToAny { .. } |
-            ExprKind::ReifyFnPointer { .. } |
-            ExprKind::ClosureFnPointer { .. } |
-            ExprKind::UnsafeFnPointer { .. } |
-            ExprKind::Unsize { .. } |
-            ExprKind::Repeat { .. } |
-            ExprKind::Borrow { .. } |
-            ExprKind::If { .. } |
-            ExprKind::Match { .. } |
-            ExprKind::Loop { .. } |
-            ExprKind::Block { .. } |
-            ExprKind::Assign { .. } |
-            ExprKind::AssignOp { .. } |
-            ExprKind::Break { .. } |
-            ExprKind::Continue { .. } |
-            ExprKind::Return { .. } |
-            ExprKind::Literal { .. } |
-            ExprKind::InlineAsm { .. } |
-            ExprKind::Yield { .. } |
-            ExprKind::Call { .. } => {
+            ExprKind::Array { .. }
+            | ExprKind::Tuple { .. }
+            | ExprKind::Adt { .. }
+            | ExprKind::Closure { .. }
+            | ExprKind::Unary { .. }
+            | ExprKind::Binary { .. }
+            | ExprKind::LogicalOp { .. }
+            | ExprKind::Box { .. }
+            | ExprKind::Cast { .. }
+            | ExprKind::Use { .. }
+            | ExprKind::NeverToAny { .. }
+            | ExprKind::ReifyFnPointer { .. }
+            | ExprKind::ClosureFnPointer { .. }
+            | ExprKind::UnsafeFnPointer { .. }
+            | ExprKind::Unsize { .. }
+            | ExprKind::Repeat { .. }
+            | ExprKind::Borrow { .. }
+            | ExprKind::If { .. }
+            | ExprKind::Match { .. }
+            | ExprKind::Loop { .. }
+            | ExprKind::Block { .. }
+            | ExprKind::Assign { .. }
+            | ExprKind::AssignOp { .. }
+            | ExprKind::Break { .. }
+            | ExprKind::Continue { .. }
+            | ExprKind::Return { .. }
+            | ExprKind::Literal { .. }
+            | ExprKind::InlineAsm { .. }
+            | ExprKind::Yield { .. }
+            | ExprKind::Call { .. } => {
                 // these are not places, so we need to make a temporary.
                 debug_assert!(match Category::of(&expr.kind) {
                     Some(Category::Place) => false,
                     _ => true,
                 });
-                let temp = unpack!(block = this.as_temp(block, expr.temp_lifetime, expr));
+                let temp =
+                    unpack!(block = this.as_temp(block, expr.temp_lifetime, expr, mutability));
                 block.and(Place::Local(temp))
             }
         }
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index b90a58f2a7e..b721120f74d 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -13,64 +13,84 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::indexed_vec::Idx;
 
-use build::{BlockAnd, BlockAndExtension, Builder};
 use build::expr::category::{Category, RvalueFunc};
+use build::{BlockAnd, BlockAndExtension, Builder};
 use hair::*;
 use rustc::middle::region;
-use rustc::ty::{self, Ty, UpvarSubsts};
-use rustc::mir::*;
 use rustc::mir::interpret::EvalErrorKind;
+use rustc::mir::*;
+use rustc::ty::{self, Ty, UpvarSubsts};
 use syntax_pos::Span;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// See comment on `as_local_operand`
-    pub fn as_local_rvalue<M>(&mut self, block: BasicBlock, expr: M)
-                             -> BlockAnd<Rvalue<'tcx>>
-        where M: Mirror<'tcx, Output = Expr<'tcx>>
+    pub fn as_local_rvalue<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Rvalue<'tcx>>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
     {
         let local_scope = self.local_scope();
         self.as_rvalue(block, local_scope, expr)
     }
 
     /// Compile `expr`, yielding an rvalue.
-    pub fn as_rvalue<M>(&mut self, block: BasicBlock, scope: Option<region::Scope>, expr: M)
-                        -> BlockAnd<Rvalue<'tcx>>
-        where M: Mirror<'tcx, Output = Expr<'tcx>>
+    pub fn as_rvalue<M>(
+        &mut self,
+        block: BasicBlock,
+        scope: Option<region::Scope>,
+        expr: M,
+    ) -> BlockAnd<Rvalue<'tcx>>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
     {
         let expr = self.hir.mirror(expr);
         self.expr_as_rvalue(block, scope, expr)
     }
 
-    fn expr_as_rvalue(&mut self,
-                      mut block: BasicBlock,
-                      scope: Option<region::Scope>,
-                      expr: Expr<'tcx>)
-                      -> BlockAnd<Rvalue<'tcx>> {
-        debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr);
+    fn expr_as_rvalue(
+        &mut self,
+        mut block: BasicBlock,
+        scope: Option<region::Scope>,
+        expr: Expr<'tcx>,
+    ) -> BlockAnd<Rvalue<'tcx>> {
+        debug!(
+            "expr_as_rvalue(block={:?}, scope={:?}, expr={:?})",
+            block, scope, expr
+        );
 
         let this = self;
         let expr_span = expr.span;
         let source_info = this.source_info(expr_span);
 
         match expr.kind {
-            ExprKind::Scope { region_scope, lint_level, value } => {
+            ExprKind::Scope {
+                region_scope,
+                lint_level,
+                value,
+            } => {
                 let region_scope = (region_scope, source_info);
-                this.in_scope(region_scope, lint_level, block,
-                              |this| this.as_rvalue(block, scope, value))
+                this.in_scope(region_scope, lint_level, block, |this| {
+                    this.as_rvalue(block, scope, value)
+                })
             }
             ExprKind::Repeat { value, count } => {
                 let value_operand = unpack!(block = this.as_operand(block, scope, value));
                 block.and(Rvalue::Repeat(value_operand, count))
             }
-            ExprKind::Borrow { region, borrow_kind, arg } => {
-                let arg_place = unpack!(block = this.as_place(block, arg));
+            ExprKind::Borrow {
+                region,
+                borrow_kind,
+                arg,
+            } => {
+                let arg_place = match borrow_kind {
+                    BorrowKind::Shared => unpack!(block = this.as_read_only_place(block, arg)),
+                    _ => unpack!(block = this.as_place(block, arg)),
+                };
                 block.and(Rvalue::Ref(region, borrow_kind, arg_place))
             }
             ExprKind::Binary { op, lhs, rhs } => {
                 let lhs = unpack!(block = this.as_operand(block, scope, lhs));
                 let rhs = unpack!(block = this.as_operand(block, scope, rhs));
-                this.build_binary_op(block, op, expr_span, expr.ty,
-                                     lhs, rhs)
+                this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs)
             }
             ExprKind::Unary { op, arg } => {
                 let arg = unpack!(block = this.as_operand(block, scope, arg));
@@ -81,11 +101,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     let minval = this.minval_literal(expr_span, expr.ty);
                     let is_min = this.temp(bool_ty, expr_span);
 
-                    this.cfg.push_assign(block, source_info, &is_min,
-                                         Rvalue::BinaryOp(BinOp::Eq, arg.to_copy(), minval));
+                    this.cfg.push_assign(
+                        block,
+                        source_info,
+                        &is_min,
+                        Rvalue::BinaryOp(BinOp::Eq, arg.to_copy(), minval),
+                    );
 
-                    block = this.assert(block, Operand::Move(is_min), false,
-                                        EvalErrorKind::OverflowNeg, expr_span);
+                    block = this.assert(
+                        block,
+                        Operand::Move(is_min),
+                        false,
+                        EvalErrorKind::OverflowNeg,
+                        expr_span,
+                    );
                 }
                 block.and(Rvalue::UnaryOp(op, arg))
             }
@@ -94,22 +123,30 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // The `Box<T>` temporary created here is not a part of the HIR,
                 // and therefore is not considered during generator OIBIT
                 // determination. See the comment about `box` at `yield_in_scope`.
-                let result = this.local_decls.push(
-                    LocalDecl::new_internal(expr.ty, expr_span));
-                this.cfg.push(block, Statement {
-                    source_info,
-                    kind: StatementKind::StorageLive(result)
-                });
+                let result = this
+                    .local_decls
+                    .push(LocalDecl::new_internal(expr.ty, expr_span));
+                this.cfg.push(
+                    block,
+                    Statement {
+                        source_info,
+                        kind: StatementKind::StorageLive(result),
+                    },
+                );
                 if let Some(scope) = scope {
                     // schedule a shallow free of that memory, lest we unwind:
                     this.schedule_drop_storage_and_value(
-                        expr_span, scope, &Place::Local(result), value.ty,
+                        expr_span,
+                        scope,
+                        &Place::Local(result),
+                        value.ty,
                     );
                 }
 
                 // malloc some memory of suitable type (thus far, uninitialized):
                 let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
-                this.cfg.push_assign(block, source_info, &Place::Local(result), box_);
+                this.cfg
+                    .push_assign(block, source_info, &Place::Local(result), box_);
 
                 // initialize the box contents:
                 unpack!(block = this.into(&Place::Local(result).deref(), block, value));
@@ -170,23 +207,29 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
                 // first process the set of fields
                 let el_ty = expr.ty.sequence_element_type(this.hir.tcx());
-                let fields: Vec<_> =
-                    fields.into_iter()
-                          .map(|f| unpack!(block = this.as_operand(block, scope, f)))
-                          .collect();
+                let fields: Vec<_> = fields
+                    .into_iter()
+                    .map(|f| unpack!(block = this.as_operand(block, scope, f)))
+                    .collect();
 
                 block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields))
             }
-            ExprKind::Tuple { fields } => { // see (*) above
+            ExprKind::Tuple { fields } => {
+                // see (*) above
                 // first process the set of fields
-                let fields: Vec<_> =
-                    fields.into_iter()
-                          .map(|f| unpack!(block = this.as_operand(block, scope, f)))
-                          .collect();
+                let fields: Vec<_> = fields
+                    .into_iter()
+                    .map(|f| unpack!(block = this.as_operand(block, scope, f)))
+                    .collect();
 
                 block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
             }
-            ExprKind::Closure { closure_id, substs, upvars, movability } => {
+            ExprKind::Closure {
+                closure_id,
+                substs,
+                upvars,
+                movability,
+            } => {
                 // see (*) above
                 let mut operands: Vec<_> = upvars
                     .into_iter()
@@ -212,25 +255,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                 // that caused the capture will cause an error.
                                 match upvar.kind {
                                     ExprKind::Borrow {
-                                        borrow_kind: BorrowKind::Mut {
-                                            allow_two_phase_borrow: false
-                                        },
+                                        borrow_kind:
+                                            BorrowKind::Mut {
+                                                allow_two_phase_borrow: false,
+                                            },
                                         region,
                                         arg,
-                                    } => unpack!(block = this.limit_capture_mutability(
-                                        upvar.span,
-                                        upvar.ty,
-                                        scope,
-                                        block,
-                                        arg,
-                                        region,
-                                    )),
+                                    } => unpack!(
+                                        block = this.limit_capture_mutability(
+                                            upvar.span, upvar.ty, scope, block, arg, region,
+                                        )
+                                    ),
                                     _ => unpack!(block = this.as_operand(block, scope, upvar)),
                                 }
                             }
                         }
-                    })
-                    .collect();
+                    }).collect();
                 let result = match substs {
                     UpvarSubsts::Generator(substs) => {
                         let movability = movability.unwrap();
@@ -248,23 +288,36 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         }));
                         box AggregateKind::Generator(closure_id, substs, movability)
                     }
-                    UpvarSubsts::Closure(substs) => {
-                        box AggregateKind::Closure(closure_id, substs)
-                    }
+                    UpvarSubsts::Closure(substs) => box AggregateKind::Closure(closure_id, substs),
                 };
                 block.and(Rvalue::Aggregate(result, operands))
             }
             ExprKind::Adt {
-                adt_def, variant_index, substs, user_ty, fields, base
-            } => { // see (*) above
+                adt_def,
+                variant_index,
+                substs,
+                user_ty,
+                fields,
+                base,
+            } => {
+                // see (*) above
                 let is_union = adt_def.is_union();
-                let active_field_index = if is_union { Some(fields[0].name.index()) } else { None };
+                let active_field_index = if is_union {
+                    Some(fields[0].name.index())
+                } else {
+                    None
+                };
 
                 // first process the set of fields that were provided
                 // (evaluating them in order given by user)
-                let fields_map: FxHashMap<_, _> = fields.into_iter()
-                    .map(|f| (f.name, unpack!(block = this.as_operand(block, scope, f.expr))))
-                    .collect();
+                let fields_map: FxHashMap<_, _> = fields
+                    .into_iter()
+                    .map(|f| {
+                        (
+                            f.name,
+                            unpack!(block = this.as_operand(block, scope, f.expr)),
+                        )
+                    }).collect();
 
                 let field_names = this.hir.all_fields(adt_def, variant_index);
 
@@ -274,15 +327,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     // MIR does not natively support FRU, so for each
                     // base-supplied field, generate an operand that
                     // reads it from the base.
-                    field_names.into_iter()
+                    field_names
+                        .into_iter()
                         .zip(field_types.into_iter())
                         .map(|(n, ty)| match fields_map.get(&n) {
                             Some(v) => v.clone(),
-                            None => this.consume_by_copy_or_move(base.clone().field(n, ty))
-                        })
-                        .collect()
+                            None => this.consume_by_copy_or_move(base.clone().field(n, ty)),
+                        }).collect()
                 } else {
-                    field_names.iter().filter_map(|n| fields_map.get(n).cloned()).collect()
+                    field_names
+                        .iter()
+                        .filter_map(|n| fields_map.get(n).cloned())
+                        .collect()
                 };
 
                 let adt = box AggregateKind::Adt(
@@ -294,8 +350,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 );
                 block.and(Rvalue::Aggregate(adt, fields))
             }
-            ExprKind::Assign { .. } |
-            ExprKind::AssignOp { .. } => {
+            ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
                 block = unpack!(this.stmt_expr(block, expr));
                 block.and(this.unit_rvalue())
             }
@@ -303,31 +358,35 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let value = unpack!(block = this.as_operand(block, scope, value));
                 let resume = this.cfg.start_new_block();
                 let cleanup = this.generator_drop_cleanup();
-                this.cfg.terminate(block, source_info, TerminatorKind::Yield {
-                    value: value,
-                    resume: resume,
-                    drop: cleanup,
-                });
+                this.cfg.terminate(
+                    block,
+                    source_info,
+                    TerminatorKind::Yield {
+                        value: value,
+                        resume: resume,
+                        drop: cleanup,
+                    },
+                );
                 resume.and(this.unit_rvalue())
             }
-            ExprKind::Literal { .. } |
-            ExprKind::Block { .. } |
-            ExprKind::Match { .. } |
-            ExprKind::If { .. } |
-            ExprKind::NeverToAny { .. } |
-            ExprKind::Loop { .. } |
-            ExprKind::LogicalOp { .. } |
-            ExprKind::Call { .. } |
-            ExprKind::Field { .. } |
-            ExprKind::Deref { .. } |
-            ExprKind::Index { .. } |
-            ExprKind::VarRef { .. } |
-            ExprKind::SelfRef |
-            ExprKind::Break { .. } |
-            ExprKind::Continue { .. } |
-            ExprKind::Return { .. } |
-            ExprKind::InlineAsm { .. } |
-            ExprKind::StaticRef { .. } => {
+            ExprKind::Literal { .. }
+            | ExprKind::Block { .. }
+            | ExprKind::Match { .. }
+            | ExprKind::If { .. }
+            | ExprKind::NeverToAny { .. }
+            | ExprKind::Loop { .. }
+            | ExprKind::LogicalOp { .. }
+            | ExprKind::Call { .. }
+            | ExprKind::Field { .. }
+            | ExprKind::Deref { .. }
+            | ExprKind::Index { .. }
+            | ExprKind::VarRef { .. }
+            | ExprKind::SelfRef
+            | ExprKind::Break { .. }
+            | ExprKind::Continue { .. }
+            | ExprKind::Return { .. }
+            | ExprKind::InlineAsm { .. }
+            | ExprKind::StaticRef { .. } => {
                 // these do not have corresponding `Rvalue` variants,
                 // so make an operand and then return that
                 debug_assert!(match Category::of(&expr.kind) {
@@ -340,19 +399,27 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn build_binary_op(&mut self, mut block: BasicBlock,
-                           op: BinOp, span: Span, ty: Ty<'tcx>,
-                           lhs: Operand<'tcx>, rhs: Operand<'tcx>) -> BlockAnd<Rvalue<'tcx>> {
+    pub fn build_binary_op(
+        &mut self,
+        mut block: BasicBlock,
+        op: BinOp,
+        span: Span,
+        ty: Ty<'tcx>,
+        lhs: Operand<'tcx>,
+        rhs: Operand<'tcx>,
+    ) -> BlockAnd<Rvalue<'tcx>> {
         let source_info = self.source_info(span);
         let bool_ty = self.hir.bool_ty();
         if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() {
             let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty]);
             let result_value = self.temp(result_tup, span);
 
-            self.cfg.push_assign(block, source_info,
-                                 &result_value, Rvalue::CheckedBinaryOp(op,
-                                                                        lhs,
-                                                                        rhs));
+            self.cfg.push_assign(
+                block,
+                source_info,
+                &result_value,
+                Rvalue::CheckedBinaryOp(op, lhs, rhs),
+            );
             let val_fld = Field::new(0);
             let of_fld = Field::new(1);
 
@@ -361,8 +428,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
             let err = EvalErrorKind::Overflow(op);
 
-            block = self.assert(block, Operand::Move(of), false,
-                                err, span);
+            block = self.assert(block, Operand::Move(of), false, err, span);
 
             block.and(Rvalue::Use(Operand::Move(val)))
         } else {
@@ -371,21 +437,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // and 2. there are two possible failure cases, divide-by-zero and overflow.
 
                 let (zero_err, overflow_err) = if op == BinOp::Div {
-                    (EvalErrorKind::DivisionByZero,
-                     EvalErrorKind::Overflow(op))
+                    (EvalErrorKind::DivisionByZero, EvalErrorKind::Overflow(op))
                 } else {
-                    (EvalErrorKind::RemainderByZero,
-                     EvalErrorKind::Overflow(op))
+                    (EvalErrorKind::RemainderByZero, EvalErrorKind::Overflow(op))
                 };
 
                 // Check for / 0
                 let is_zero = self.temp(bool_ty, span);
                 let zero = self.zero_literal(span, ty);
-                self.cfg.push_assign(block, source_info, &is_zero,
-                                     Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), zero));
+                self.cfg.push_assign(
+                    block,
+                    source_info,
+                    &is_zero,
+                    Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), zero),
+                );
 
-                block = self.assert(block, Operand::Move(is_zero), false,
-                                    zero_err, span);
+                block = self.assert(block, Operand::Move(is_zero), false, zero_err, span);
 
                 // We only need to check for the overflow in one case:
                 // MIN / -1, and only for signed values.
@@ -394,23 +461,34 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     let min = self.minval_literal(span, ty);
 
                     let is_neg_1 = self.temp(bool_ty, span);
-                    let is_min   = self.temp(bool_ty, span);
-                    let of       = self.temp(bool_ty, span);
+                    let is_min = self.temp(bool_ty, span);
+                    let of = self.temp(bool_ty, span);
 
                     // this does (rhs == -1) & (lhs == MIN). It could short-circuit instead
 
-                    self.cfg.push_assign(block, source_info, &is_neg_1,
-                                         Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), neg_1));
-                    self.cfg.push_assign(block, source_info, &is_min,
-                                         Rvalue::BinaryOp(BinOp::Eq, lhs.to_copy(), min));
+                    self.cfg.push_assign(
+                        block,
+                        source_info,
+                        &is_neg_1,
+                        Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), neg_1),
+                    );
+                    self.cfg.push_assign(
+                        block,
+                        source_info,
+                        &is_min,
+                        Rvalue::BinaryOp(BinOp::Eq, lhs.to_copy(), min),
+                    );
 
                     let is_neg_1 = Operand::Move(is_neg_1);
                     let is_min = Operand::Move(is_min);
-                    self.cfg.push_assign(block, source_info, &of,
-                                         Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min));
+                    self.cfg.push_assign(
+                        block,
+                        source_info,
+                        &of,
+                        Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min),
+                    );
 
-                    block = self.assert(block, Operand::Move(of), false,
-                                        overflow_err, span);
+                    block = self.assert(block, Operand::Move(of), false, overflow_err, span);
                 }
             }
 
@@ -430,12 +508,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let this = self;
 
         let source_info = this.source_info(upvar_span);
-        let temp = this.local_decls.push(LocalDecl::new_temp(upvar_ty, upvar_span));
+        let temp = this
+            .local_decls
+            .push(LocalDecl::new_temp(upvar_ty, upvar_span));
 
-        this.cfg.push(block, Statement {
-            source_info,
-            kind: StatementKind::StorageLive(temp)
-        });
+        this.cfg.push(
+            block,
+            Statement {
+                source_info,
+                kind: StatementKind::StorageLive(temp),
+            },
+        );
 
         let arg_place = unpack!(block = this.as_place(block, arg));
 
@@ -446,8 +529,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 elem: ProjectionElem::Deref,
             }) => {
                 debug_assert!(
-                    if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard))
-                        = this.local_decls[local].is_user_variable {
+                    if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) =
+                        this.local_decls[local].is_user_variable
+                    {
                         true
                     } else {
                         false
@@ -461,10 +545,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 elem: ProjectionElem::Field(upvar_index, _),
             })
             | Place::Projection(box Projection {
-                base: Place::Projection(box Projection {
-                    ref base,
-                    elem: ProjectionElem::Field(upvar_index, _),
-                }),
+                base:
+                    Place::Projection(box Projection {
+                        ref base,
+                        elem: ProjectionElem::Field(upvar_index, _),
+                    }),
                 elem: ProjectionElem::Deref,
             }) => {
                 // Not projected from the implicit `self` in a closure.
@@ -491,7 +576,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         let borrow_kind = match mutability {
             Mutability::Not => BorrowKind::Unique,
-            Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
+            Mutability::Mut => BorrowKind::Mut {
+                allow_two_phase_borrow: false,
+            },
         };
 
         this.cfg.push_assign(
@@ -506,7 +593,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         // a constant at this time, even if the type may need dropping.
         if let Some(temp_lifetime) = temp_lifetime {
             this.schedule_drop_storage_and_value(
-                upvar_span, temp_lifetime, &Place::Local(temp), upvar_ty,
+                upvar_span,
+                temp_lifetime,
+                &Place::Local(temp),
+                upvar_ty,
             );
         }
 
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index f66fe763b75..a2dcce6adcb 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -18,42 +18,63 @@ use rustc::mir::*;
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Compile `expr` into a fresh temporary. This is used when building
     /// up rvalues so as to freeze the value that will be consumed.
-    pub fn as_temp<M>(&mut self,
-                      block: BasicBlock,
-                      temp_lifetime: Option<region::Scope>,
-                      expr: M)
-                      -> BlockAnd<Local>
-        where M: Mirror<'tcx, Output = Expr<'tcx>>
+    pub fn as_temp<M>(
+        &mut self,
+        block: BasicBlock,
+        temp_lifetime: Option<region::Scope>,
+        expr: M,
+        mutability: Mutability,
+    ) -> BlockAnd<Local>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
     {
         let expr = self.hir.mirror(expr);
-        self.expr_as_temp(block, temp_lifetime, expr)
+        self.expr_as_temp(block, temp_lifetime, expr, mutability)
     }
 
-    fn expr_as_temp(&mut self,
-                    mut block: BasicBlock,
-                    temp_lifetime: Option<region::Scope>,
-                    expr: Expr<'tcx>)
-                    -> BlockAnd<Local> {
-        debug!("expr_as_temp(block={:?}, temp_lifetime={:?}, expr={:?})",
-               block, temp_lifetime, expr);
+    fn expr_as_temp(
+        &mut self,
+        mut block: BasicBlock,
+        temp_lifetime: Option<region::Scope>,
+        expr: Expr<'tcx>,
+        mutability: Mutability,
+    ) -> BlockAnd<Local> {
+        debug!(
+            "expr_as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})",
+            block, temp_lifetime, expr, mutability
+        );
         let this = self;
 
         let expr_span = expr.span;
         let source_info = this.source_info(expr_span);
-        if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
+        if let ExprKind::Scope {
+            region_scope,
+            lint_level,
+            value,
+        } = expr.kind
+        {
             return this.in_scope((region_scope, source_info), lint_level, block, |this| {
-                this.as_temp(block, temp_lifetime, value)
+                this.as_temp(block, temp_lifetime, value, mutability)
             });
         }
 
         let expr_ty = expr.ty;
-        let temp = this.local_decls.push(LocalDecl::new_temp(expr_ty, expr_span));
+        let temp = if mutability == Mutability::Not {
+            this.local_decls
+                .push(LocalDecl::new_immutable_temp(expr_ty, expr_span))
+        } else {
+            this.local_decls
+                .push(LocalDecl::new_temp(expr_ty, expr_span))
+        };
 
         if !expr_ty.is_never() {
-            this.cfg.push(block, Statement {
-                source_info,
-                kind: StatementKind::StorageLive(temp)
-            });
+            this.cfg.push(
+                block,
+                Statement {
+                    source_info,
+                    kind: StatementKind::StorageLive(temp),
+                },
+            );
         }
 
         unpack!(block = this.into(&Place::Local(temp), block, expr));
@@ -63,7 +84,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         // a constant at this time, even if the type may need dropping.
         if let Some(temp_lifetime) = temp_lifetime {
             this.schedule_drop_storage_and_value(
-                expr_span, temp_lifetime, &Place::Local(temp), expr_ty,
+                expr_span,
+                temp_lifetime,
+                &Place::Local(temp),
+                expr_ty,
             );
         }
 
diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs
index bce8e97d481..601fe2d01f8 100644
--- a/src/librustc_mir/build/expr/category.rs
+++ b/src/librustc_mir/build/expr/category.rs
@@ -45,53 +45,51 @@ impl Category {
         match *ek {
             ExprKind::Scope { .. } => None,
 
-            ExprKind::Field { .. } |
-            ExprKind::Deref { .. } |
-            ExprKind::Index { .. } |
-            ExprKind::SelfRef |
-            ExprKind::VarRef { .. } |
-            ExprKind::StaticRef { .. } =>
-                Some(Category::Place),
+            ExprKind::Field { .. }
+            | ExprKind::Deref { .. }
+            | ExprKind::Index { .. }
+            | ExprKind::SelfRef
+            | ExprKind::VarRef { .. }
+            | ExprKind::StaticRef { .. } => Some(Category::Place),
 
-            ExprKind::LogicalOp { .. } |
-            ExprKind::If { .. } |
-            ExprKind::Match { .. } |
-            ExprKind::NeverToAny { .. } |
-            ExprKind::Call { .. } =>
-                Some(Category::Rvalue(RvalueFunc::Into)),
+            ExprKind::LogicalOp { .. }
+            | ExprKind::If { .. }
+            | ExprKind::Match { .. }
+            | ExprKind::NeverToAny { .. }
+            | ExprKind::Call { .. } => Some(Category::Rvalue(RvalueFunc::Into)),
 
-            ExprKind::Array { .. } |
-            ExprKind::Tuple { .. } |
-            ExprKind::Adt { .. } |
-            ExprKind::Closure { .. } |
-            ExprKind::Unary { .. } |
-            ExprKind::Binary { .. } |
-            ExprKind::Box { .. } |
-            ExprKind::Cast { .. } |
-            ExprKind::Use { .. } |
-            ExprKind::ReifyFnPointer { .. } |
-            ExprKind::ClosureFnPointer { .. } |
-            ExprKind::UnsafeFnPointer { .. } |
-            ExprKind::Unsize { .. } |
-            ExprKind::Repeat { .. } |
-            ExprKind::Borrow { .. } |
-            ExprKind::Assign { .. } |
-            ExprKind::AssignOp { .. } |
-            ExprKind::Yield { .. } |
-            ExprKind::InlineAsm { .. } =>
-                Some(Category::Rvalue(RvalueFunc::AsRvalue)),
+            ExprKind::Array { .. }
+            | ExprKind::Tuple { .. }
+            | ExprKind::Adt { .. }
+            | ExprKind::Closure { .. }
+            | ExprKind::Unary { .. }
+            | ExprKind::Binary { .. }
+            | ExprKind::Box { .. }
+            | ExprKind::Cast { .. }
+            | ExprKind::Use { .. }
+            | ExprKind::ReifyFnPointer { .. }
+            | ExprKind::ClosureFnPointer { .. }
+            | ExprKind::UnsafeFnPointer { .. }
+            | ExprKind::Unsize { .. }
+            | ExprKind::Repeat { .. }
+            | ExprKind::Borrow { .. }
+            | ExprKind::Assign { .. }
+            | ExprKind::AssignOp { .. }
+            | ExprKind::Yield { .. }
+            | ExprKind::InlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
 
-            ExprKind::Literal { .. } =>
-                Some(Category::Constant),
+            ExprKind::Literal { .. } => Some(Category::Constant),
 
-            ExprKind::Loop { .. } |
-            ExprKind::Block { .. } |
-            ExprKind::Break { .. } |
-            ExprKind::Continue { .. } |
-            ExprKind::Return { .. } =>
-                // FIXME(#27840) these probably want their own
-                // category, like "nonterminating"
-                Some(Category::Rvalue(RvalueFunc::Into)),
+            ExprKind::Loop { .. }
+            | ExprKind::Block { .. }
+            | ExprKind::Break { .. }
+            | ExprKind::Continue { .. }
+            | ExprKind::Return { .. } =>
+            // FIXME(#27840) these probably want their own
+            // category, like "nonterminating"
+            {
+                Some(Category::Rvalue(RvalueFunc::Into))
+            }
         }
     }
 }
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 3cd1270d7ef..59ebb7703ff 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -10,25 +10,27 @@
 
 //! See docs in build/expr/mod.rs
 
-use build::{BlockAnd, BlockAndExtension, Builder};
 use build::expr::category::{Category, RvalueFunc};
+use build::{BlockAnd, BlockAndExtension, Builder};
 use hair::*;
-use rustc::ty;
 use rustc::mir::*;
+use rustc::ty;
 
 use rustc_target::spec::abi::Abi;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Compile `expr`, storing the result into `destination`, which
     /// is assumed to be uninitialized.
-    pub fn into_expr(&mut self,
-                     destination: &Place<'tcx>,
-                     mut block: BasicBlock,
-                     expr: Expr<'tcx>)
-                     -> BlockAnd<()>
-    {
-        debug!("into_expr(destination={:?}, block={:?}, expr={:?})",
-               destination, block, expr);
+    pub fn into_expr(
+        &mut self,
+        destination: &Place<'tcx>,
+        mut block: BasicBlock,
+        expr: Expr<'tcx>,
+    ) -> BlockAnd<()> {
+        debug!(
+            "into_expr(destination={:?}, block={:?}, expr={:?})",
+            destination, block, expr
+        );
 
         // since we frequently have to reference `self` from within a
         // closure, where `self` would be shadowed, it's easier to
@@ -38,10 +40,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let source_info = this.source_info(expr_span);
 
         match expr.kind {
-            ExprKind::Scope { region_scope, lint_level, value } => {
+            ExprKind::Scope {
+                region_scope,
+                lint_level,
+                value,
+            } => {
                 let region_scope = (region_scope, source_info);
-                this.in_scope(region_scope, lint_level, block,
-                              |this| this.into(destination, block, value))
+                this.in_scope(region_scope, lint_level, block, |this| {
+                    this.into(destination, block, value)
+                })
             }
             ExprKind::Block { body: ast_block } => {
                 this.ast_block(destination, block, ast_block, source_info)
@@ -63,12 +70,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 if is_call {
                     block.unit()
                 } else {
-                    this.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
+                    this.cfg
+                        .terminate(block, source_info, TerminatorKind::Unreachable);
                     let end_block = this.cfg.start_new_block();
                     end_block.unit()
                 }
             }
-            ExprKind::If { condition: cond_expr, then: then_expr, otherwise: else_expr } => {
+            ExprKind::If {
+                condition: cond_expr,
+                then: then_expr,
+                otherwise: else_expr,
+            } => {
                 let operand = unpack!(block = this.as_local_operand(block, cond_expr));
 
                 let mut then_block = this.cfg.start_new_block();
@@ -82,15 +94,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 } else {
                     // Body of the `if` expression without an `else` clause must return `()`, thus
                     // we implicitly generate a `else {}` if it is not specified.
-                    this.cfg.push_assign_unit(else_block, source_info, destination);
+                    this.cfg
+                        .push_assign_unit(else_block, source_info, destination);
                     else_block
                 };
 
                 let join_block = this.cfg.start_new_block();
-                this.cfg.terminate(then_block, source_info,
-                                   TerminatorKind::Goto { target: join_block });
-                this.cfg.terminate(else_block, source_info,
-                                   TerminatorKind::Goto { target: join_block });
+                this.cfg.terminate(
+                    then_block,
+                    source_info,
+                    TerminatorKind::Goto { target: join_block },
+                );
+                this.cfg.terminate(
+                    else_block,
+                    source_info,
+                    TerminatorKind::Goto { target: join_block },
+                );
 
                 join_block.unit()
             }
@@ -107,9 +126,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 //        | (true)                   | (false)
                 //  [true_block]               [false_block]
 
-                let (true_block, false_block, mut else_block, join_block) =
-                    (this.cfg.start_new_block(), this.cfg.start_new_block(),
-                     this.cfg.start_new_block(), this.cfg.start_new_block());
+                let (true_block, false_block, mut else_block, join_block) = (
+                    this.cfg.start_new_block(),
+                    this.cfg.start_new_block(),
+                    this.cfg.start_new_block(),
+                    this.cfg.start_new_block(),
+                );
 
                 let lhs = unpack!(block = this.as_local_operand(block, lhs));
                 let blocks = match op {
@@ -124,31 +146,46 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 this.cfg.terminate(else_block, source_info, term);
 
                 this.cfg.push_assign_constant(
-                    true_block, source_info, destination,
+                    true_block,
+                    source_info,
+                    destination,
                     Constant {
                         span: expr_span,
                         ty: this.hir.bool_ty(),
                         user_ty: None,
                         literal: this.hir.true_literal(),
-                    });
+                    },
+                );
 
                 this.cfg.push_assign_constant(
-                    false_block, source_info, destination,
+                    false_block,
+                    source_info,
+                    destination,
                     Constant {
                         span: expr_span,
                         ty: this.hir.bool_ty(),
                         user_ty: None,
                         literal: this.hir.false_literal(),
-                    });
+                    },
+                );
 
-                this.cfg.terminate(true_block, source_info,
-                                   TerminatorKind::Goto { target: join_block });
-                this.cfg.terminate(false_block, source_info,
-                                   TerminatorKind::Goto { target: join_block });
+                this.cfg.terminate(
+                    true_block,
+                    source_info,
+                    TerminatorKind::Goto { target: join_block },
+                );
+                this.cfg.terminate(
+                    false_block,
+                    source_info,
+                    TerminatorKind::Goto { target: join_block },
+                );
 
                 join_block.unit()
             }
-            ExprKind::Loop { condition: opt_cond_expr, body } => {
+            ExprKind::Loop {
+                condition: opt_cond_expr,
+                body,
+            } => {
                 // [block] --> [loop_block] -/eval. cond./-> [loop_block_end] -1-> [exit_block]
                 //                  ^                               |
                 //                  |                               0
@@ -172,35 +209,45 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let exit_block = this.cfg.start_new_block();
 
                 // start the loop
-                this.cfg.terminate(block, source_info,
-                                   TerminatorKind::Goto { target: loop_block });
+                this.cfg.terminate(
+                    block,
+                    source_info,
+                    TerminatorKind::Goto { target: loop_block },
+                );
 
                 this.in_breakable_scope(
-                    Some(loop_block), exit_block, destination.clone(),
+                    Some(loop_block),
+                    exit_block,
+                    destination.clone(),
                     move |this| {
                         // conduct the test, if necessary
                         let body_block;
                         if let Some(cond_expr) = opt_cond_expr {
                             let loop_block_end;
                             let cond = unpack!(
-                                loop_block_end = this.as_local_operand(loop_block, cond_expr));
+                                loop_block_end = this.as_local_operand(loop_block, cond_expr)
+                            );
                             body_block = this.cfg.start_new_block();
-                            let term = TerminatorKind::if_(this.hir.tcx(), cond,
-                                                           body_block, exit_block);
+                            let term =
+                                TerminatorKind::if_(this.hir.tcx(), cond, body_block, exit_block);
                             this.cfg.terminate(loop_block_end, source_info, term);
 
                             // if the test is false, there's no `break` to assign `destination`, so
                             // we have to do it; this overwrites any `break`-assigned value but it's
                             // always `()` anyway
-                            this.cfg.push_assign_unit(exit_block, source_info, destination);
+                            this.cfg
+                                .push_assign_unit(exit_block, source_info, destination);
                         } else {
                             body_block = this.cfg.start_new_block();
                             let diverge_cleanup = this.diverge_cleanup();
-                            this.cfg.terminate(loop_block, source_info,
-                                               TerminatorKind::FalseUnwind {
-                                                   real_target: body_block,
-                                                   unwind: Some(diverge_cleanup)
-                                               })
+                            this.cfg.terminate(
+                                loop_block,
+                                source_info,
+                                TerminatorKind::FalseUnwind {
+                                    real_target: body_block,
+                                    unwind: Some(diverge_cleanup),
+                                },
+                            )
                         }
 
                         // The “return” value of the loop body must always be an unit. We therefore
@@ -208,9 +255,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         let tmp = this.get_unit_temp();
                         // Execute the body, branching back to the test.
                         let body_block_end = unpack!(this.into(&tmp, body_block, body));
-                        this.cfg.terminate(body_block_end, source_info,
-                                           TerminatorKind::Goto { target: loop_block });
-                    }
+                        this.cfg.terminate(
+                            body_block_end,
+                            source_info,
+                            TerminatorKind::Goto { target: loop_block },
+                        );
+                    },
                 );
                 exit_block.unit()
             }
@@ -218,16 +268,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // FIXME(canndrew): This is_never should probably be an is_uninhabited
                 let diverges = expr.ty.is_never();
                 let intrinsic = match ty.sty {
-                    ty::FnDef(def_id, _)  => {
+                    ty::FnDef(def_id, _) => {
                         let f = ty.fn_sig(this.hir.tcx());
-                        if f.abi() == Abi::RustIntrinsic ||
-                           f.abi() == Abi::PlatformIntrinsic {
+                        if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
                             Some(this.hir.tcx().item_name(def_id).as_str())
                         } else {
                             None
                         }
                     }
-                    _ => None
+                    _ => None,
                 };
                 let intrinsic = intrinsic.as_ref().map(|s| &s[..]);
                 let fun = unpack!(block = this.as_local_operand(block, fun));
@@ -257,95 +306,99 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     let block = unpack!(this.into(&ptr_temp, block, ptr));
                     this.into(&ptr_temp.deref(), block, val)
                 } else {
-                    let args: Vec<_> =
-                        args.into_iter()
-                            .map(|arg| unpack!(block = this.as_local_operand(block, arg)))
-                            .collect();
+                    let args: Vec<_> = args
+                        .into_iter()
+                        .map(|arg| unpack!(block = this.as_local_operand(block, arg)))
+                        .collect();
 
                     let success = this.cfg.start_new_block();
                     let cleanup = this.diverge_cleanup();
-                    this.cfg.terminate(block, source_info, TerminatorKind::Call {
-                        func: fun,
-                        args,
-                        cleanup: Some(cleanup),
-                        destination: if diverges {
-                            None
-                        } else {
-                            Some ((destination.clone(), success))
-                        }
-                    });
+                    this.cfg.terminate(
+                        block,
+                        source_info,
+                        TerminatorKind::Call {
+                            func: fun,
+                            args,
+                            cleanup: Some(cleanup),
+                            destination: if diverges {
+                                None
+                            } else {
+                                Some((destination.clone(), success))
+                            },
+                        },
+                    );
                     success.unit()
                 }
             }
 
             // These cases don't actually need a destination
-            ExprKind::Assign { .. } |
-            ExprKind::AssignOp { .. } |
-            ExprKind::Continue { .. } |
-            ExprKind::Break { .. } |
-            ExprKind::InlineAsm { .. } |
-            ExprKind::Return { .. } => {
+            ExprKind::Assign { .. }
+            | ExprKind::AssignOp { .. }
+            | ExprKind::Continue { .. }
+            | ExprKind::Break { .. }
+            | ExprKind::InlineAsm { .. }
+            | ExprKind::Return { .. } => {
                 unpack!(block = this.stmt_expr(block, expr));
                 this.cfg.push_assign_unit(block, source_info, destination);
                 block.unit()
             }
 
             // Avoid creating a temporary
-            ExprKind::VarRef { .. } |
-            ExprKind::SelfRef |
-            ExprKind::StaticRef { .. } => {
+            ExprKind::VarRef { .. } | ExprKind::SelfRef | ExprKind::StaticRef { .. } => {
                 debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
 
                 let place = unpack!(block = this.as_place(block, expr));
                 let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
-                this.cfg.push_assign(block, source_info, destination, rvalue);
+                this.cfg
+                    .push_assign(block, source_info, destination, rvalue);
                 block.unit()
             }
-            ExprKind::Index { .. } |
-            ExprKind::Deref { .. } |
-            ExprKind::Field { .. } => {
+            ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => {
                 debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
 
                 // Create a "fake" temporary variable so that we check that the
                 // value is Sized. Usually, this is caught in type checking, but
                 // in the case of box expr there is no such check.
                 if let Place::Projection(..) = destination {
-                    this.local_decls.push(LocalDecl::new_temp(expr.ty, expr.span));
+                    this.local_decls
+                        .push(LocalDecl::new_temp(expr.ty, expr.span));
                 }
 
                 debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
 
                 let place = unpack!(block = this.as_place(block, expr));
                 let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
-                this.cfg.push_assign(block, source_info, destination, rvalue);
+                this.cfg
+                    .push_assign(block, source_info, destination, rvalue);
                 block.unit()
             }
 
             // these are the cases that are more naturally handled by some other mode
-            ExprKind::Unary { .. } |
-            ExprKind::Binary { .. } |
-            ExprKind::Box { .. } |
-            ExprKind::Cast { .. } |
-            ExprKind::Use { .. } |
-            ExprKind::ReifyFnPointer { .. } |
-            ExprKind::ClosureFnPointer { .. } |
-            ExprKind::UnsafeFnPointer { .. } |
-            ExprKind::Unsize { .. } |
-            ExprKind::Repeat { .. } |
-            ExprKind::Borrow { .. } |
-            ExprKind::Array { .. } |
-            ExprKind::Tuple { .. } |
-            ExprKind::Adt { .. } |
-            ExprKind::Closure { .. } |
-            ExprKind::Literal { .. } |
-            ExprKind::Yield { .. } => {
+            ExprKind::Unary { .. }
+            | ExprKind::Binary { .. }
+            | ExprKind::Box { .. }
+            | ExprKind::Cast { .. }
+            | ExprKind::Use { .. }
+            | ExprKind::ReifyFnPointer { .. }
+            | ExprKind::ClosureFnPointer { .. }
+            | ExprKind::UnsafeFnPointer { .. }
+            | ExprKind::Unsize { .. }
+            | ExprKind::Repeat { .. }
+            | ExprKind::Borrow { .. }
+            | ExprKind::Array { .. }
+            | ExprKind::Tuple { .. }
+            | ExprKind::Adt { .. }
+            | ExprKind::Closure { .. }
+            | ExprKind::Literal { .. }
+            | ExprKind::Yield { .. } => {
                 debug_assert!(match Category::of(&expr.kind).unwrap() {
                     Category::Rvalue(RvalueFunc::Into) => false,
                     _ => true,
                 });
 
                 let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
-                this.cfg.push_assign(block, source_info, destination, rvalue);
+                this.cfg
+                    .push_assign(block, source_info, destination, rvalue);
                 block.unit()
             }
         }
diff --git a/src/librustc_mir/build/expr/mod.rs b/src/librustc_mir/build/expr/mod.rs
index a63cf41f066..6442ba34da4 100644
--- a/src/librustc_mir/build/expr/mod.rs
+++ b/src/librustc_mir/build/expr/mod.rs
@@ -71,9 +71,9 @@
 //! over to the "by reference" mode (`as_place`).
 
 mod as_constant;
+mod as_operand;
 mod as_place;
 mod as_rvalue;
-mod as_operand;
 mod as_temp;
 mod category;
 mod into;
diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs
index 6f1fe833578..0086cff46e5 100644
--- a/src/librustc_mir/build/expr/stmt.rs
+++ b/src/librustc_mir/build/expr/stmt.rs
@@ -8,13 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use build::{BlockAnd, BlockAndExtension, Builder};
 use build::scope::BreakableScope;
+use build::{BlockAnd, BlockAndExtension, Builder};
 use hair::*;
 use rustc::mir::*;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
-
     pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd<()> {
         let this = self;
         let expr_span = expr.span;
@@ -22,7 +21,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         // Handle a number of expressions that don't need a destination at all. This
         // avoids needing a mountain of temporary `()` variables.
         match expr.kind {
-            ExprKind::Scope { region_scope, lint_level, value } => {
+            ExprKind::Scope {
+                region_scope,
+                lint_level,
+                value,
+            } => {
                 let value = this.hir.mirror(value);
                 this.in_scope((region_scope, source_info), lint_level, block, |this| {
                     this.stmt_expr(block, value)
@@ -42,9 +45,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 if this.hir.needs_drop(lhs.ty) {
                     let rhs = unpack!(block = this.as_local_operand(block, rhs));
                     let lhs = unpack!(block = this.as_place(block, lhs));
-                    unpack!(block = this.build_drop_and_replace(
-                        block, lhs_span, lhs, rhs
-                    ));
+                    unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs));
                     block.unit()
                 } else {
                     let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
@@ -72,18 +73,34 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // we don't have to drop prior contents or anything
                 // because AssignOp is only legal for Copy types
                 // (overloaded ops should be desugared into a call).
-                let result = unpack!(block = this.build_binary_op(block, op, expr_span, lhs_ty,
-                                                  Operand::Copy(lhs.clone()), rhs));
+                let result = unpack!(
+                    block = this.build_binary_op(
+                        block,
+                        op,
+                        expr_span,
+                        lhs_ty,
+                        Operand::Copy(lhs.clone()),
+                        rhs
+                    )
+                );
                 this.cfg.push_assign(block, source_info, &lhs, result);
 
                 block.unit()
             }
             ExprKind::Continue { label } => {
-                let BreakableScope { continue_block, region_scope, .. } =
-                    *this.find_breakable_scope(expr_span, label);
-                let continue_block = continue_block.expect(
-                    "Attempted to continue in non-continuable breakable block");
-                this.exit_scope(expr_span, (region_scope, source_info), block, continue_block);
+                let BreakableScope {
+                    continue_block,
+                    region_scope,
+                    ..
+                } = *this.find_breakable_scope(expr_span, label);
+                let continue_block = continue_block
+                    .expect("Attempted to continue in non-continuable breakable block");
+                this.exit_scope(
+                    expr_span,
+                    (region_scope, source_info),
+                    block,
+                    continue_block,
+                );
                 this.cfg.start_new_block().unit()
             }
             ExprKind::Break { label, value } => {
@@ -106,13 +123,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
             ExprKind::Return { value } => {
                 block = match value {
-                    Some(value) => {
-                        unpack!(this.into(&Place::Local(RETURN_PLACE), block, value))
-                    }
+                    Some(value) => unpack!(this.into(&Place::Local(RETURN_PLACE), block, value)),
                     None => {
-                        this.cfg.push_assign_unit(block,
-                                                  source_info,
-                                                  &Place::Local(RETURN_PLACE));
+                        this.cfg
+                            .push_assign_unit(block, source_info, &Place::Local(RETURN_PLACE));
                         block
                     }
                 };
@@ -121,21 +135,30 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 this.exit_scope(expr_span, (region_scope, source_info), block, return_block);
                 this.cfg.start_new_block().unit()
             }
-            ExprKind::InlineAsm { asm, outputs, inputs } => {
-                let outputs = outputs.into_iter().map(|output| {
-                    unpack!(block = this.as_place(block, output))
-                }).collect();
-                let inputs = inputs.into_iter().map(|input| {
-                    unpack!(block = this.as_local_operand(block, input))
-                }).collect();
-                this.cfg.push(block, Statement {
-                    source_info,
-                    kind: StatementKind::InlineAsm {
-                        asm: box asm.clone(),
-                        outputs,
-                        inputs,
+            ExprKind::InlineAsm {
+                asm,
+                outputs,
+                inputs,
+            } => {
+                let outputs = outputs
+                    .into_iter()
+                    .map(|output| unpack!(block = this.as_place(block, output)))
+                    .collect();
+                let inputs = inputs
+                    .into_iter()
+                    .map(|input| unpack!(block = this.as_local_operand(block, input)))
+                    .collect();
+                this.cfg.push(
+                    block,
+                    Statement {
+                        source_info,
+                        kind: StatementKind::InlineAsm {
+                            asm: box asm.clone(),
+                            outputs,
+                            inputs,
+                        },
                     },
-                });
+                );
                 block.unit()
             }
             _ => {
@@ -147,5 +170,4 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
         }
     }
-
 }
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs
index 995e70fb382..f42612b4b7a 100644
--- a/src/librustc_mir/dataflow/impls/borrows.rs
+++ b/src/librustc_mir/dataflow/impls/borrows.rs
@@ -153,7 +153,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
         nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
         def_id: DefId,
         body_id: Option<hir::BodyId>,
-        borrow_set: &Rc<BorrowSet<'tcx>>
+        borrow_set: &Rc<BorrowSet<'tcx>>,
     ) -> Self {
         let scope_tree = tcx.region_scope_tree(def_id);
         let root_scope = body_id.map(|body_id| {
@@ -269,7 +269,13 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
                 // propagate_call_return method.
 
                 if let mir::Rvalue::Ref(region, _, ref place) = *rhs {
-                    if place.ignore_borrow(self.tcx, self.mir) { return; }
+                    if place.ignore_borrow(
+                        self.tcx,
+                        self.mir,
+                        &self.borrow_set.locals_state_at_exit,
+                    ) {
+                        return;
+                    }
                     let index = self.borrow_set.location_map.get(&location).unwrap_or_else(|| {
                         panic!("could not find BorrowIndex for location {:?}", location);
                     });
diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs
index 8728afc228f..7d7da6c96e8 100644
--- a/src/librustc_mir/dataflow/move_paths/mod.rs
+++ b/src/librustc_mir/dataflow/move_paths/mod.rs
@@ -334,4 +334,14 @@ impl<'a, 'gcx, 'tcx> MoveData<'tcx> {
                         -> Result<Self, (Self, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
         builder::gather_moves(mir, tcx)
     }
+
+    /// For the move path `mpi`, returns the root local variable (if any) that starts the path.
+    /// (e.g., for a path like `a.b.c` returns `Some(a)`)
+    pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> {
+        loop {
+            let path = &self.move_paths[mpi];
+            if let Place::Local(l) = path.place { return Some(l); }
+            if let Some(parent) = path.parent { mpi = parent; continue } else { return None }
+        }
+    }
 }
diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs
index e0643d8f978..9f5b5040b09 100644
--- a/src/librustc_mir/util/pretty.rs
+++ b/src/librustc_mir/util/pretty.rs
@@ -612,8 +612,9 @@ fn write_temp_decls(mir: &Mir, w: &mut dyn Write) -> io::Result<()> {
     for temp in mir.temps_iter() {
         writeln!(
             w,
-            "{}let mut {:?}: {};",
+            "{}let {}{:?}: {};",
             INDENT,
+            if mir.local_decls[temp].mutability == Mutability::Mut {"mut "} else {""},
             temp,
             mir.local_decls[temp].ty
         )?;
diff --git a/src/test/mir-opt/end_region_destruction_extents_1.rs b/src/test/mir-opt/end_region_destruction_extents_1.rs
index 8f8c406bcb3..16e2fe046fb 100644
--- a/src/test/mir-opt/end_region_destruction_extents_1.rs
+++ b/src/test/mir-opt/end_region_destruction_extents_1.rs
@@ -70,10 +70,10 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
 //     let mut _2: D1<'12ds, '10s>;
 //     let mut _3: &'12ds S1;
 //     let mut _4: &'12ds S1;
-//     let mut _5: S1;
+//     let _5: S1;
 //     let mut _6: &'10s S1;
 //     let mut _7: &'10s S1;
-//     let mut _8: S1;
+//     let _8: S1;
 //     bb0: {
 //         StorageLive(_2);
 //         StorageLive(_3);
@@ -118,10 +118,10 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
 //     let mut _2: D1<'12ds, '10s>;
 //     let mut _3: &'12ds S1;
 //     let mut _4: &'12ds S1;
-//     let mut _5: S1;
+//     let _5: S1;
 //     let mut _6: &'10s S1;
 //     let mut _7: &'10s S1;
-//     let mut _8: S1;
+//     let _8: S1;
 //     bb0: {
 //         StorageLive(_2);
 //         StorageLive(_3);
diff --git a/src/test/mir-opt/storage_live_dead_in_statics.rs b/src/test/mir-opt/storage_live_dead_in_statics.rs
index 730ef655b13..e39b7df8a7a 100644
--- a/src/test/mir-opt/storage_live_dead_in_statics.rs
+++ b/src/test/mir-opt/storage_live_dead_in_statics.rs
@@ -47,11 +47,11 @@ fn main() {
 // START rustc.XXX.mir_map.0.mir
 //    let mut _0: &'static Foo;
 //    let mut _1: &'static Foo;
-//    let mut _2: Foo;
+//    let _2: Foo;
 //    let mut _3: &'static [(u32, u32)];
 //    let mut _4: &'static [(u32, u32); 42];
 //    let mut _5: &'static [(u32, u32); 42];
-//    let mut _6: [(u32, u32); 42];
+//    let _6: [(u32, u32); 42];
 //    let mut _7: (u32, u32);
 //    let mut _8: (u32, u32);
 //    let mut _9: (u32, u32);