diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs
index 079541235a25e..dfd292176d2f9 100644
--- a/src/libcollections/fmt.rs
+++ b/src/libcollections/fmt.rs
@@ -524,6 +524,7 @@ use string;
 pub fn format(args: Arguments) -> string::String {
     let capacity = args.estimated_capacity();
     let mut output = string::String::with_capacity(capacity);
-    let _ = output.write_fmt(args);
+    output.write_fmt(args)
+          .expect("a formatting trait implementation returned an error");
     output
 }
diff --git a/src/libcollections/macros.rs b/src/libcollections/macros.rs
index 3115be00a4d72..396a917dfde26 100644
--- a/src/libcollections/macros.rs
+++ b/src/libcollections/macros.rs
@@ -72,6 +72,12 @@ macro_rules! vec {
 ///
 /// [fmt]: ../std/fmt/index.html
 ///
+/// # Panics
+///
+/// `format!` panics if a formatting trait implementation returns an error.
+/// This indicates an incorrect implementation
+/// since `fmt::Write for String` never returns an error itself.
+///
 /// # Examples
 ///
 /// ```
diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs
index 4b37aef860d72..f2e4be49684a9 100644
--- a/src/libcollections/string.rs
+++ b/src/libcollections/string.rs
@@ -1900,13 +1900,20 @@ pub trait ToString {
     fn to_string(&self) -> String;
 }
 
+/// # Panics
+///
+/// In this implementation, the `to_string` method panics
+/// if the `Display` implementation returns an error.
+/// This indicates an incorrect `Display` implementation
+/// since `fmt::Write for String` never returns an error itself.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: fmt::Display + ?Sized> ToString for T {
     #[inline]
     default fn to_string(&self) -> String {
         use core::fmt::Write;
         let mut buf = String::new();
-        let _ = buf.write_fmt(format_args!("{}", self));
+        buf.write_fmt(format_args!("{}", self))
+           .expect("a Display implementation return an error unexpectedly");
         buf.shrink_to_fit();
         buf
     }
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index b33caefbcd2ec..0516e111be3b3 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -125,6 +125,10 @@ pub mod __internal {
         fn register_attr_proc_macro(&mut self,
                                     name: &str,
                                     expand: fn(TokenStream, TokenStream) -> TokenStream);
+
+        fn register_bang_proc_macro(&mut self,
+                                    name: &str,
+                                    expand: fn(TokenStream) -> TokenStream);
     }
 
     // Emulate scoped_thread_local!() here essentially
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 40ebc97a78a6c..10761a03bec0c 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -983,7 +983,7 @@ pub enum Rvalue<'tcx> {
     Use(Operand<'tcx>),
 
     /// [x; 32]
-    Repeat(Operand<'tcx>, TypedConstVal<'tcx>),
+    Repeat(Operand<'tcx>, ConstUsize),
 
     /// &x or &mut x
     Ref(&'tcx Region, BorrowKind, Lvalue<'tcx>),
@@ -1038,7 +1038,8 @@ pub enum CastKind {
 
 #[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub enum AggregateKind<'tcx> {
-    Array,
+    /// The type is of the element
+    Array(Ty<'tcx>),
     Tuple,
     /// The second field is variant number (discriminant), it's equal to 0
     /// for struct and union expressions. The fourth field is active field
@@ -1135,7 +1136,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                 }
 
                 match *kind {
-                    AggregateKind::Array => write!(fmt, "{:?}", lvs),
+                    AggregateKind::Array(_) => write!(fmt, "{:?}", lvs),
 
                     AggregateKind::Tuple => {
                         match lvs.len() {
@@ -1202,19 +1203,6 @@ pub struct Constant<'tcx> {
     pub literal: Literal<'tcx>,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable)]
-pub struct TypedConstVal<'tcx> {
-    pub ty: Ty<'tcx>,
-    pub span: Span,
-    pub value: ConstUsize,
-}
-
-impl<'tcx> Debug for TypedConstVal<'tcx> {
-    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
-        write!(fmt, "const {}", ConstInt::Usize(self.value))
-    }
-}
-
 newtype_index!(Promoted, "promoted");
 
 #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 50a80305bee27..14d3876a66e55 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -134,46 +134,45 @@ impl<'tcx> Lvalue<'tcx> {
 }
 
 impl<'tcx> Rvalue<'tcx> {
-    pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Ty<'tcx>>
+    pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>
     {
         match *self {
-            Rvalue::Use(ref operand) => Some(operand.ty(mir, tcx)),
+            Rvalue::Use(ref operand) => operand.ty(mir, tcx),
             Rvalue::Repeat(ref operand, ref count) => {
                 let op_ty = operand.ty(mir, tcx);
-                let count = count.value.as_u64(tcx.sess.target.uint_type);
+                let count = count.as_u64(tcx.sess.target.uint_type);
                 assert_eq!(count as usize as u64, count);
-                Some(tcx.mk_array(op_ty, count as usize))
+                tcx.mk_array(op_ty, count as usize)
             }
             Rvalue::Ref(reg, bk, ref lv) => {
                 let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
-                Some(tcx.mk_ref(reg,
+                tcx.mk_ref(reg,
                     ty::TypeAndMut {
                         ty: lv_ty,
                         mutbl: bk.to_mutbl_lossy()
                     }
-                ))
+                )
             }
-            Rvalue::Len(..) => Some(tcx.types.usize),
-            Rvalue::Cast(.., ty) => Some(ty),
+            Rvalue::Len(..) => tcx.types.usize,
+            Rvalue::Cast(.., ty) => ty,
             Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
                 let lhs_ty = lhs.ty(mir, tcx);
                 let rhs_ty = rhs.ty(mir, tcx);
-                Some(op.ty(tcx, lhs_ty, rhs_ty))
+                op.ty(tcx, lhs_ty, rhs_ty)
             }
             Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
                 let lhs_ty = lhs.ty(mir, tcx);
                 let rhs_ty = rhs.ty(mir, tcx);
                 let ty = op.ty(tcx, lhs_ty, rhs_ty);
-                let ty = tcx.intern_tup(&[ty, tcx.types.bool], false);
-                Some(ty)
+                tcx.intern_tup(&[ty, tcx.types.bool], false)
             }
             Rvalue::UnaryOp(_, ref operand) => {
-                Some(operand.ty(mir, tcx))
+                operand.ty(mir, tcx)
             }
             Rvalue::Discriminant(ref lval) => {
                 let ty = lval.ty(mir, tcx).to_ty(tcx);
                 if let ty::TyAdt(adt_def, _) = ty.sty {
-                    Some(adt_def.repr.discr_type().to_ty(tcx))
+                    adt_def.repr.discr_type().to_ty(tcx)
                 } else {
                     // Undefined behaviour, bug for now; may want to return something for
                     // the `discriminant` intrinsic later.
@@ -181,29 +180,24 @@ impl<'tcx> Rvalue<'tcx> {
                 }
             }
             Rvalue::Box(t) => {
-                Some(tcx.mk_box(t))
+                tcx.mk_box(t)
             }
             Rvalue::Aggregate(ref ak, ref ops) => {
                 match *ak {
-                    AggregateKind::Array => {
-                        if let Some(operand) = ops.get(0) {
-                            let ty = operand.ty(mir, tcx);
-                            Some(tcx.mk_array(ty, ops.len()))
-                        } else {
-                            None
-                        }
+                    AggregateKind::Array(ty) => {
+                        tcx.mk_array(ty, ops.len())
                     }
                     AggregateKind::Tuple => {
-                        Some(tcx.mk_tup(
+                        tcx.mk_tup(
                             ops.iter().map(|op| op.ty(mir, tcx)),
                             false
-                        ))
+                        )
                     }
                     AggregateKind::Adt(def, _, substs, _) => {
-                        Some(tcx.item_type(def.did).subst(tcx, substs))
+                        tcx.item_type(def.did).subst(tcx, substs)
                     }
                     AggregateKind::Closure(did, substs) => {
-                        Some(tcx.mk_closure_from_closure_substs(did, substs))
+                        tcx.mk_closure_from_closure_substs(did, substs)
                     }
                 }
             }
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 7cdbd5cae061f..980d1806e78f8 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -235,12 +235,6 @@ macro_rules! make_mir_visitor {
                 self.super_const_usize(const_usize);
             }
 
-            fn visit_typed_const_val(&mut self,
-                                     val: & $($mutability)* TypedConstVal<'tcx>,
-                                     location: Location) {
-                self.super_typed_const_val(val, location);
-            }
-
             fn visit_local_decl(&mut self,
                                 local_decl: & $($mutability)* LocalDecl<'tcx>) {
                 self.super_local_decl(local_decl);
@@ -467,9 +461,9 @@ macro_rules! make_mir_visitor {
                     }
 
                     Rvalue::Repeat(ref $($mutability)* value,
-                                   ref $($mutability)* typed_const_val) => {
+                                   ref $($mutability)* length) => {
                         self.visit_operand(value, location);
-                        self.visit_typed_const_val(typed_const_val, location);
+                        self.visit_const_usize(length, location);
                     }
 
                     Rvalue::Ref(r, bk, ref $($mutability)* path) => {
@@ -515,7 +509,8 @@ macro_rules! make_mir_visitor {
                     Rvalue::Aggregate(ref $($mutability)* kind,
                                       ref $($mutability)* operands) => {
                         match *kind {
-                            AggregateKind::Array => {
+                            AggregateKind::Array(ref $($mutability)* ty) => {
+                                self.visit_ty(ty);
                             }
                             AggregateKind::Tuple => {
                             }
@@ -647,20 +642,6 @@ macro_rules! make_mir_visitor {
                 self.visit_literal(literal, location);
             }
 
-            fn super_typed_const_val(&mut self,
-                                     constant: & $($mutability)* TypedConstVal<'tcx>,
-                                     location: Location) {
-                let TypedConstVal {
-                    ref $($mutability)* span,
-                    ref $($mutability)* ty,
-                    ref $($mutability)* value,
-                } = *constant;
-
-                self.visit_span(span);
-                self.visit_ty(ty);
-                self.visit_const_usize(value, location);
-            }
-
             fn super_literal(&mut self,
                              literal: & $($mutability)* Literal<'tcx>,
                              location: Location) {
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index f850fd9772781..99db5f9b62435 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -986,7 +986,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder) {
         let current_limit = self.tcx.sess.recursion_limit.get();
         let suggested_limit = current_limit * 2;
-        err.note(&format!(
+        err.help(&format!(
                           "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
                           suggested_limit));
     }
diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
index 13f898219bc12..a71d23e7e1e7e 100644
--- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
+++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
@@ -161,6 +161,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
     fn create_drop_flag(&mut self, index: MovePathIndex) {
         let tcx = self.tcx;
         let patch = &mut self.patch;
+        debug!("create_drop_flag({:?})", self.mir.span);
         self.drop_flags.entry(index).or_insert_with(|| {
             patch.new_temp(tcx.types.bool)
         });
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 4477488f6cb38..49dcffb4830a1 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -586,7 +586,7 @@ impl<'a> CrateLoader<'a> {
         use proc_macro::__internal::Registry;
         use rustc_back::dynamic_lib::DynamicLibrary;
         use syntax_ext::deriving::custom::ProcMacroDerive;
-        use syntax_ext::proc_macro_impl::AttrProcMacro;
+        use syntax_ext::proc_macro_impl::{AttrProcMacro, BangProcMacro};
 
         let path = match dylib {
             Some(dylib) => dylib,
@@ -630,6 +630,15 @@ impl<'a> CrateLoader<'a> {
                 );
                 self.0.push((Symbol::intern(name), Rc::new(expand)));
             }
+
+            fn register_bang_proc_macro(&mut self,
+                                        name: &str,
+                                        expand: fn(TokenStream) -> TokenStream) {
+                let expand = SyntaxExtension::ProcMacro(
+                    Box::new(BangProcMacro { inner: expand })
+                );
+                self.0.push((Symbol::intern(name), Rc::new(expand)));
+            }
         }
 
         let mut my_registrar = MyRegistrar(Vec::new());
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index 121d592da0316..3305cfc0dfe1a 100644
--- a/src/librustc_mir/build/block.rs
+++ b/src/librustc_mir/build/block.rs
@@ -67,7 +67,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                 this.expr_into_pattern(block, pattern, init)
                             }));
                         } else {
-                            this.storage_live_for_bindings(block, &pattern);
+                            this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| {
+                                this.storage_live_binding(block, node, span);
+                                this.schedule_drop_for_binding(node, span);
+                            })
                         }
 
                         // Enter the visibility scope, after evaluating the initializer.
diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs
index 5abfe084f2258..8886a310429ea 100644
--- a/src/librustc_mir/build/expr/as_lvalue.rs
+++ b/src/librustc_mir/build/expr/as_lvalue.rs
@@ -56,8 +56,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let (usize_ty, bool_ty) = (this.hir.usize_ty(), this.hir.bool_ty());
 
                 let slice = unpack!(block = this.as_lvalue(block, lhs));
-
-                let idx = unpack!(block = this.as_operand(block, index));
+                // extent=None so lvalue 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_operand(block, None, index));
 
                 // bounds check:
                 let (len, lt) = (this.temp(usize_ty.clone()), this.temp(bool_ty));
@@ -121,7 +123,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     Some(Category::Lvalue) => false,
                     _ => true,
                 });
-                this.as_temp(block, expr)
+                this.as_temp(block, expr.temp_lifetime, expr)
             }
         }
     }
diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs
index 09cdcc74ef63e..8d79e755685d0 100644
--- a/src/librustc_mir/build/expr/as_operand.rs
+++ b/src/librustc_mir/build/expr/as_operand.rs
@@ -13,29 +13,52 @@
 use build::{BlockAnd, BlockAndExtension, Builder};
 use build::expr::category::Category;
 use hair::*;
+use rustc::middle::region::CodeExtent;
 use rustc::mir::*;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
+    /// Returns an operand suitable for use until the end of the current
+    /// scope expression.
+    ///
+    /// 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>>
+    {
+        let topmost_scope = self.topmost_scope(); // FIXME(#6393)
+        self.as_operand(block, Some(topmost_scope), expr)
+    }
+
     /// Compile `expr` into a value that can be used as an operand.
     /// If `expr` is an lvalue like `x`, this will introduce a
     /// temporary `tmp = x`, so that we capture the value of `x` at
     /// this time.
-    pub fn as_operand<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Operand<'tcx>>
+    ///
+    /// The operand is known to be live until the end of `scope`.
+    pub fn as_operand<M>(&mut self,
+                         block: BasicBlock,
+                         scope: Option<CodeExtent>,
+                         expr: M) -> BlockAnd<Operand<'tcx>>
         where M: Mirror<'tcx, Output = Expr<'tcx>>
     {
         let expr = self.hir.mirror(expr);
-        self.expr_as_operand(block, expr)
+        self.expr_as_operand(block, scope, expr)
     }
 
     fn expr_as_operand(&mut self,
                        mut block: BasicBlock,
+                       scope: Option<CodeExtent>,
                        expr: Expr<'tcx>)
                        -> BlockAnd<Operand<'tcx>> {
         debug!("expr_as_operand(block={:?}, expr={:?})", block, expr);
         let this = self;
 
         if let ExprKind::Scope { extent, value } = expr.kind {
-            return this.in_scope(extent, block, |this| this.as_operand(block, value));
+            return this.in_scope(extent, block, |this| {
+                this.as_operand(block, scope, value)
+            });
         }
 
         let category = Category::of(&expr.kind).unwrap();
@@ -47,7 +70,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
             Category::Lvalue |
             Category::Rvalue(..) => {
-                let operand = unpack!(block = this.as_temp(block, expr));
+                let operand =
+                    unpack!(block = this.as_temp(block, scope, expr));
                 block.and(Operand::Consume(operand))
             }
         }
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 7f5d9c36ecedf..6694107a8d485 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -21,22 +21,34 @@ use build::expr::category::{Category, RvalueFunc};
 use hair::*;
 use rustc_const_math::{ConstInt, ConstIsize};
 use rustc::middle::const_val::ConstVal;
+use rustc::middle::region::CodeExtent;
 use rustc::ty;
 use rustc::mir::*;
 use syntax::ast;
 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>>
+    {
+        let topmost_scope = self.topmost_scope(); // FIXME(#6393)
+        self.as_rvalue(block, Some(topmost_scope), expr)
+    }
+
     /// Compile `expr`, yielding an rvalue.
-    pub fn as_rvalue<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Rvalue<'tcx>>
+    pub fn as_rvalue<M>(&mut self, block: BasicBlock, scope: Option<CodeExtent>, expr: M)
+                        -> BlockAnd<Rvalue<'tcx>>
         where M: Mirror<'tcx, Output = Expr<'tcx>>
     {
         let expr = self.hir.mirror(expr);
-        self.expr_as_rvalue(block, expr)
+        self.expr_as_rvalue(block, scope, expr)
     }
 
     fn expr_as_rvalue(&mut self,
                       mut block: BasicBlock,
+                      scope: Option<CodeExtent>,
                       expr: Expr<'tcx>)
                       -> BlockAnd<Rvalue<'tcx>> {
         debug!("expr_as_rvalue(block={:?}, expr={:?})", block, expr);
@@ -47,10 +59,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         match expr.kind {
             ExprKind::Scope { extent, value } => {
-                this.in_scope(extent, block, |this| this.as_rvalue(block, value))
+                this.in_scope(extent, block, |this| this.as_rvalue(block, scope, value))
             }
             ExprKind::Repeat { value, count } => {
-                let value_operand = unpack!(block = this.as_operand(block, value));
+                let value_operand = unpack!(block = this.as_operand(block, scope, value));
                 block.and(Rvalue::Repeat(value_operand, count))
             }
             ExprKind::Borrow { region, borrow_kind, arg } => {
@@ -58,13 +70,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 block.and(Rvalue::Ref(region, borrow_kind, arg_lvalue))
             }
             ExprKind::Binary { op, lhs, rhs } => {
-                let lhs = unpack!(block = this.as_operand(block, lhs));
-                let rhs = unpack!(block = this.as_operand(block, 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)
             }
             ExprKind::Unary { op, arg } => {
-                let arg = unpack!(block = this.as_operand(block, arg));
+                let arg = unpack!(block = this.as_operand(block, scope, arg));
                 // Check for -MIN on signed integers
                 if this.hir.check_overflow() && op == UnOp::Neg && expr.ty.is_signed() {
                     let bool_ty = this.hir.bool_ty();
@@ -97,27 +109,27 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             ExprKind::Cast { source } => {
                 let source = this.hir.mirror(source);
 
-                let source = unpack!(block = this.as_operand(block, source));
+                let source = unpack!(block = this.as_operand(block, scope, source));
                 block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
             }
             ExprKind::Use { source } => {
-                let source = unpack!(block = this.as_operand(block, source));
+                let source = unpack!(block = this.as_operand(block, scope, source));
                 block.and(Rvalue::Use(source))
             }
             ExprKind::ReifyFnPointer { source } => {
-                let source = unpack!(block = this.as_operand(block, source));
+                let source = unpack!(block = this.as_operand(block, scope, source));
                 block.and(Rvalue::Cast(CastKind::ReifyFnPointer, source, expr.ty))
             }
             ExprKind::UnsafeFnPointer { source } => {
-                let source = unpack!(block = this.as_operand(block, source));
+                let source = unpack!(block = this.as_operand(block, scope, source));
                 block.and(Rvalue::Cast(CastKind::UnsafeFnPointer, source, expr.ty))
             }
             ExprKind::ClosureFnPointer { source } => {
-                let source = unpack!(block = this.as_operand(block, source));
+                let source = unpack!(block = this.as_operand(block, scope, source));
                 block.and(Rvalue::Cast(CastKind::ClosureFnPointer, source, expr.ty))
             }
             ExprKind::Unsize { source } => {
-                let source = unpack!(block = this.as_operand(block, source));
+                let source = unpack!(block = this.as_operand(block, scope, source));
                 block.and(Rvalue::Cast(CastKind::Unsize, source, expr.ty))
             }
             ExprKind::Array { fields } => {
@@ -148,18 +160,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 //     to the same MIR as `let x = ();`.
 
                 // 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, f)))
+                          .map(|f| unpack!(block = this.as_operand(block, scope, f)))
                           .collect();
 
-                block.and(Rvalue::Aggregate(AggregateKind::Array, fields))
+                block.and(Rvalue::Aggregate(AggregateKind::Array(el_ty), fields))
             }
             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, f)))
+                          .map(|f| unpack!(block = this.as_operand(block, scope, f)))
                           .collect();
 
                 block.and(Rvalue::Aggregate(AggregateKind::Tuple, fields))
@@ -167,7 +180,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             ExprKind::Closure { closure_id, substs, upvars } => { // see (*) above
                 let upvars =
                     upvars.into_iter()
-                          .map(|upvar| unpack!(block = this.as_operand(block, upvar)))
+                          .map(|upvar| unpack!(block = this.as_operand(block, scope, upvar)))
                           .collect();
                 block.and(Rvalue::Aggregate(AggregateKind::Closure(closure_id, substs), upvars))
             }
@@ -179,10 +192,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
                 // 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, 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);
 
@@ -235,7 +247,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     Some(Category::Rvalue(RvalueFunc::AsRvalue)) => false,
                     _ => true,
                 });
-                let operand = unpack!(block = this.as_operand(block, expr));
+                let operand = unpack!(block = this.as_operand(block, scope, expr));
                 block.and(Rvalue::Use(operand))
             }
         }
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index 0ae4bcc4205d4..69b9570200921 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -13,29 +13,38 @@
 use build::{BlockAnd, BlockAndExtension, Builder};
 use build::expr::category::Category;
 use hair::*;
+use rustc::middle::region::CodeExtent;
 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, expr: M) -> BlockAnd<Lvalue<'tcx>>
+    pub fn as_temp<M>(&mut self,
+                      block: BasicBlock,
+                      temp_lifetime: Option<CodeExtent>,
+                      expr: M)
+                      -> BlockAnd<Lvalue<'tcx>>
         where M: Mirror<'tcx, Output = Expr<'tcx>>
     {
         let expr = self.hir.mirror(expr);
-        self.expr_as_temp(block, expr)
+        self.expr_as_temp(block, temp_lifetime, expr)
     }
 
-    fn expr_as_temp(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd<Lvalue<'tcx>> {
+    fn expr_as_temp(&mut self,
+                    mut block: BasicBlock,
+                    temp_lifetime: Option<CodeExtent>,
+                    expr: Expr<'tcx>)
+                    -> BlockAnd<Lvalue<'tcx>> {
         debug!("expr_as_temp(block={:?}, expr={:?})", block, expr);
         let this = self;
 
-        if let ExprKind::Scope { extent, value } = expr.kind {
-            return this.in_scope(extent, block, |this| this.as_temp(block, value));
+        if let ExprKind::Scope { .. } = expr.kind {
+            span_bug!(expr.span, "unexpected scope expression in as_temp: {:?}",
+                      expr);
         }
 
         let expr_ty = expr.ty.clone();
         let temp = this.temp(expr_ty.clone());
-        let temp_lifetime = expr.temp_lifetime;
         let expr_span = expr.span;
         let source_info = this.source_info(expr_span);
 
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index ae51951b519bd..dab8510687329 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -52,7 +52,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     _ => false,
                 };
 
-                unpack!(block = this.as_rvalue(block, source));
+                unpack!(block = this.as_local_rvalue(block, source));
 
                 // This is an optimization. If the expression was a call then we already have an
                 // unreachable block. Don't bother to terminate it and create a new one.
@@ -65,7 +65,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 }
             }
             ExprKind::If { condition: cond_expr, then: then_expr, otherwise: else_expr } => {
-                let operand = unpack!(block = this.as_operand(block, cond_expr));
+                let operand = unpack!(block = this.as_local_operand(block, cond_expr));
 
                 let mut then_block = this.cfg.start_new_block();
                 let mut else_block = this.cfg.start_new_block();
@@ -107,7 +107,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     (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_operand(block, lhs));
+                let lhs = unpack!(block = this.as_local_operand(block, lhs));
                 let blocks = match op {
                     LogicalOp::And => (else_block, false_block),
                     LogicalOp::Or => (true_block, else_block),
@@ -115,7 +115,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1);
                 this.cfg.terminate(block, source_info, term);
 
-                let rhs = unpack!(else_block = this.as_operand(else_block, rhs));
+                let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
                 let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block);
                 this.cfg.terminate(else_block, source_info, term);
 
@@ -173,7 +173,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         if let Some(cond_expr) = opt_cond_expr {
                             let loop_block_end;
                             let cond = unpack!(
-                                loop_block_end = this.as_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);
@@ -206,10 +206,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     }
                     _ => false
                 };
-                let fun = unpack!(block = this.as_operand(block, fun));
+                let fun = unpack!(block = this.as_local_operand(block, fun));
                 let args: Vec<_> =
                     args.into_iter()
-                        .map(|arg| unpack!(block = this.as_operand(block, arg)))
+                        .map(|arg| unpack!(block = this.as_local_operand(block, arg)))
                         .collect();
 
                 let success = this.cfg.start_new_block();
@@ -265,7 +265,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     _ => true,
                 });
 
-                let rvalue = unpack!(block = this.as_rvalue(block, expr));
+                let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
                 this.cfg.push_assign(block, source_info, destination, rvalue);
                 block.unit()
             }
diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs
index c577aab40dbeb..be39dcbf6d08d 100644
--- a/src/librustc_mir/build/expr/stmt.rs
+++ b/src/librustc_mir/build/expr/stmt.rs
@@ -38,14 +38,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // Generate better code for things that don't need to be
                 // dropped.
                 if this.hir.needs_drop(lhs.ty) {
-                    let rhs = unpack!(block = this.as_operand(block, rhs));
+                    let rhs = unpack!(block = this.as_local_operand(block, rhs));
                     let lhs = unpack!(block = this.as_lvalue(block, lhs));
                     unpack!(block = this.build_drop_and_replace(
                         block, lhs_span, lhs, rhs
                     ));
                     block.unit()
                 } else {
-                    let rhs = unpack!(block = this.as_rvalue(block, rhs));
+                    let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
                     let lhs = unpack!(block = this.as_lvalue(block, lhs));
                     this.cfg.push_assign(block, source_info, &lhs, rhs);
                     block.unit()
@@ -64,7 +64,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let lhs_ty = lhs.ty;
 
                 // As above, RTL.
-                let rhs = unpack!(block = this.as_operand(block, rhs));
+                let rhs = unpack!(block = this.as_local_operand(block, rhs));
                 let lhs = unpack!(block = this.as_lvalue(block, lhs));
 
                 // we don't have to drop prior contents or anything
@@ -122,7 +122,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     unpack!(block = this.as_lvalue(block, output))
                 }).collect();
                 let inputs = inputs.into_iter().map(|input| {
-                    unpack!(block = this.as_operand(block, input))
+                    unpack!(block = this.as_local_operand(block, input))
                 }).collect();
                 this.cfg.push(block, Statement {
                     source_info: source_info,
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 6b6acb054b1b0..705eb1f56608e 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -123,16 +123,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             PatternKind::Binding { mode: BindingMode::ByValue,
                                    var,
                                    subpattern: None, .. } => {
-                self.storage_live_for_bindings(block, &irrefutable_pat);
-                let lvalue = Lvalue::Local(self.var_indices[&var]);
-                return self.into(&lvalue, block, initializer);
+                let lvalue = self.storage_live_binding(block, var, irrefutable_pat.span);
+                unpack!(block = self.into(&lvalue, block, initializer));
+                self.schedule_drop_for_binding(var, irrefutable_pat.span);
+                block.unit()
+            }
+            _ => {
+                let lvalue = unpack!(block = self.as_lvalue(block, initializer));
+                self.lvalue_into_pattern(block, irrefutable_pat, &lvalue)
             }
-            _ => {}
         }
-        let lvalue = unpack!(block = self.as_lvalue(block, initializer));
-        self.lvalue_into_pattern(block,
-                                 irrefutable_pat,
-                                 &lvalue)
     }
 
     pub fn lvalue_into_pattern(&mut self,
@@ -174,79 +174,70 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             scope_span: Span,
                             pattern: &Pattern<'tcx>)
                             -> Option<VisibilityScope> {
-        match *pattern.kind {
-            PatternKind::Binding { mutability, name, mode: _, var, ty, ref subpattern } => {
-                if var_scope.is_none() {
-                    var_scope = Some(self.new_visibility_scope(scope_span));
-                }
-                let source_info = SourceInfo {
-                    span: pattern.span,
-                    scope: var_scope.unwrap()
-                };
-                self.declare_binding(source_info, mutability, name, var, ty);
-                if let Some(subpattern) = subpattern.as_ref() {
-                    var_scope = self.declare_bindings(var_scope, scope_span, subpattern);
-                }
-            }
-            PatternKind::Array { ref prefix, ref slice, ref suffix } |
-            PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
-                for subpattern in prefix.iter().chain(slice).chain(suffix) {
-                    var_scope = self.declare_bindings(var_scope, scope_span, subpattern);
-                }
-            }
-            PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
-            }
-            PatternKind::Deref { ref subpattern } => {
-                var_scope = self.declare_bindings(var_scope, scope_span, subpattern);
-            }
-            PatternKind::Leaf { ref subpatterns } |
-            PatternKind::Variant { ref subpatterns, .. } => {
-                for subpattern in subpatterns {
-                    var_scope = self.declare_bindings(var_scope, scope_span, &subpattern.pattern);
-                }
+        self.visit_bindings(pattern, &mut |this, mutability, name, var, span, ty| {
+            if var_scope.is_none() {
+                var_scope = Some(this.new_visibility_scope(scope_span));
             }
-        }
+            let source_info = SourceInfo {
+                span: span,
+                scope: var_scope.unwrap()
+            };
+            this.declare_binding(source_info, mutability, name, var, ty);
+        });
         var_scope
     }
 
-    /// Emit `StorageLive` for every binding in the pattern.
-    pub fn storage_live_for_bindings(&mut self,
-                                     block: BasicBlock,
-                                     pattern: &Pattern<'tcx>) {
-        match *pattern.kind {
-            PatternKind::Binding { var, ref subpattern, .. } => {
-                let lvalue = Lvalue::Local(self.var_indices[&var]);
-                let source_info = self.source_info(pattern.span);
-                self.cfg.push(block, Statement {
-                    source_info: source_info,
-                    kind: StatementKind::StorageLive(lvalue)
-                });
+    pub fn storage_live_binding(&mut self, block: BasicBlock, var: NodeId, span: Span)
+                            -> Lvalue<'tcx>
+    {
+        let local_id = self.var_indices[&var];
+        let source_info = self.source_info(span);
+        self.cfg.push(block, Statement {
+            source_info: source_info,
+            kind: StatementKind::StorageLive(Lvalue::Local(local_id))
+        });
+        Lvalue::Local(local_id)
+    }
 
+    pub fn schedule_drop_for_binding(&mut self, var: NodeId, span: Span) {
+        let local_id = self.var_indices[&var];
+        let var_ty = self.local_decls[local_id].ty;
+        let extent = self.hir.tcx().region_maps.var_scope(var);
+        self.schedule_drop(span, extent, &Lvalue::Local(local_id), var_ty);
+    }
+
+    pub fn visit_bindings<F>(&mut self, pattern: &Pattern<'tcx>, mut f: &mut F)
+        where F: FnMut(&mut Self, Mutability, Name, NodeId, Span, Ty<'tcx>)
+    {
+        match *pattern.kind {
+            PatternKind::Binding { mutability, name, var, ty, ref subpattern, .. } => {
+                f(self, mutability, name, var, pattern.span, ty);
                 if let Some(subpattern) = subpattern.as_ref() {
-                    self.storage_live_for_bindings(block, subpattern);
+                    self.visit_bindings(subpattern, f);
                 }
             }
             PatternKind::Array { ref prefix, ref slice, ref suffix } |
             PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
                 for subpattern in prefix.iter().chain(slice).chain(suffix) {
-                    self.storage_live_for_bindings(block, subpattern);
+                    self.visit_bindings(subpattern, f);
                 }
             }
             PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
             }
             PatternKind::Deref { ref subpattern } => {
-                self.storage_live_for_bindings(block, subpattern);
+                self.visit_bindings(subpattern, f);
             }
             PatternKind::Leaf { ref subpatterns } |
             PatternKind::Variant { ref subpatterns, .. } => {
                 for subpattern in subpatterns {
-                    self.storage_live_for_bindings(block, &subpattern.pattern);
+                    self.visit_bindings(&subpattern.pattern, f);
                 }
             }
         }
     }
 }
 
+
 /// List of blocks for each arm (and potentially other metadata in the
 /// future).
 struct ArmBlocks {
@@ -670,7 +661,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             // guard, this block is simply unreachable
             let guard = self.hir.mirror(guard);
             let source_info = self.source_info(guard.span);
-            let cond = unpack!(block = self.as_operand(block, guard));
+            let cond = unpack!(block = self.as_local_operand(block, guard));
             let otherwise = self.cfg.start_new_block();
             self.cfg.terminate(block, source_info,
                                TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise));
@@ -691,25 +682,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         // Assign each of the bindings. This may trigger moves out of the candidate.
         for binding in bindings {
-            // Find the variable for the `var_id` being bound. It
-            // should have been created by a previous call to
-            // `declare_bindings`.
-            let var_index = self.var_indices[&binding.var_id];
-
+            let source_info = self.source_info(binding.span);
+            let local = self.storage_live_binding(block, binding.var_id, binding.span);
+            self.schedule_drop_for_binding(binding.var_id, binding.span);
             let rvalue = match binding.binding_mode {
                 BindingMode::ByValue =>
                     Rvalue::Use(Operand::Consume(binding.source)),
                 BindingMode::ByRef(region, borrow_kind) =>
                     Rvalue::Ref(region, borrow_kind, binding.source),
             };
-
-            let source_info = self.source_info(binding.span);
-            self.cfg.push(block, Statement {
-                source_info: source_info,
-                kind: StatementKind::StorageLive(Lvalue::Local(var_index))
-            });
-            self.cfg.push_assign(block, source_info,
-                                 &Lvalue::Local(var_index), rvalue);
+            self.cfg.push_assign(block, source_info, &local, rvalue);
         }
     }
 
@@ -730,8 +712,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             name: Some(name),
             source_info: Some(source_info),
         });
-        let extent = self.hir.tcx().region_maps.var_scope(var_id);
-        self.schedule_drop(source_info.span, extent, &Lvalue::Local(var), var_ty);
         self.var_indices.insert(var_id, var);
 
         debug!("declare_binding: var={:?}", var);
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 282361fc13e27..3dab1717f6b2e 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -253,9 +253,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             f: F)
         where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>)
     {
-        let extent = self.scopes.last().map(|scope| scope.extent).unwrap();
+        let extent = self.topmost_scope();
         let loop_scope = LoopScope {
-            extent: extent.clone(),
+            extent: extent,
             continue_block: loop_block,
             break_block: break_block,
             break_destination: break_destination,
@@ -416,6 +416,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         self.scopes[1].extent
     }
 
+    /// Returns the topmost active scope, which is known to be alive until
+    /// the next scope expression.
+    pub fn topmost_scope(&self) -> CodeExtent {
+        self.scopes.last().expect("topmost_scope: no scopes present").extent
+    }
+
     // Scheduling drops
     // ================
     /// Indicates that `lvalue` should be dropped on exit from
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index f2b89309e4ab1..c67bb8ec6c585 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -602,11 +602,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
             ExprKind::Repeat {
                 value: v.to_ref(),
-                count: TypedConstVal {
-                    ty: cx.tcx.types.usize,
-                    span: c.span,
-                    value: count
-                }
+                count: count,
             }
         }
         hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() },
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 9c7ee6a9ce883..2ee375dee08ac 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -14,7 +14,8 @@
 //! unit-tested and separated from the Rust source and compiler data
 //! structures.
 
-use rustc::mir::{BinOp, BorrowKind, Field, Literal, UnOp, TypedConstVal};
+use rustc_const_math::ConstUsize;
+use rustc::mir::{BinOp, BorrowKind, Field, Literal, UnOp};
 use rustc::hir::def_id::DefId;
 use rustc::middle::region::CodeExtent;
 use rustc::ty::subst::Substs;
@@ -219,7 +220,7 @@ pub enum ExprKind<'tcx> {
     },
     Repeat {
         value: ExprRef<'tcx>,
-        count: TypedConstVal<'tcx>,
+        count: ConstUsize,
     },
     Array {
         fields: Vec<ExprRef<'tcx>>,
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 441a9add883dd..e998665e03536 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -752,7 +752,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                     }
 
                     if Some(def.did) == self.tcx.lang_items.unsafe_cell_type() {
-                        let ty = rvalue.ty(self.mir, self.tcx).unwrap();
+                        let ty = rvalue.ty(self.mir, self.tcx);
                         self.add_type(ty);
                         assert!(self.qualif.intersects(Qualif::MUTABLE_INTERIOR));
                         // Even if the value inside may not need dropping,
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index af4a4a53905eb..c99c4323bb8a1 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -83,9 +83,8 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
 
     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
         self.super_rvalue(rvalue, location);
-        if let Some(ty) = rvalue.ty(self.mir, self.tcx()) {
-            self.sanitize_type(rvalue, ty);
-        }
+        let rval_ty = rvalue.ty(self.mir, self.tcx());
+        self.sanitize_type(rvalue, rval_ty);
     }
 
     fn visit_mir(&mut self, mir: &Mir<'tcx>) {
@@ -356,14 +355,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             StatementKind::Assign(ref lv, ref rv) => {
                 let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
                 let rv_ty = rv.ty(mir, tcx);
-                if let Some(rv_ty) = rv_ty {
-                    if let Err(terr) = self.sub_types(rv_ty, lv_ty) {
-                        span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}",
-                                     lv_ty, rv_ty, terr);
-                    }
+                if let Err(terr) = self.sub_types(rv_ty, lv_ty) {
+                    span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}",
+                                 lv_ty, rv_ty, terr);
                 }
-                // FIXME: rvalue with undeterminable type - e.g. AggregateKind::Array branch that
-                // returns `None`.
             }
             StatementKind::SetDiscriminant{ ref lvalue, variant_index } => {
                 let lvalue_type = lvalue.ty(mir, tcx).to_ty(tcx);
diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs
index ad20c535decbb..ce02cb0e83643 100644
--- a/src/librustc_passes/mir_stats.rs
+++ b/src/librustc_passes/mir_stats.rs
@@ -19,7 +19,7 @@ use rustc::mir::{Constant, Literal, Location, LocalDecl};
 use rustc::mir::{Lvalue, LvalueElem, LvalueProjection};
 use rustc::mir::{Mir, Operand, ProjectionElem};
 use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind};
-use rustc::mir::{Terminator, TerminatorKind, TypedConstVal, VisibilityScope, VisibilityScopeData};
+use rustc::mir::{Terminator, TerminatorKind, VisibilityScope, VisibilityScopeData};
 use rustc::mir::visit as mir_visit;
 use rustc::mir::visit::Visitor;
 use rustc::ty::{ClosureSubsts, TyCtxt};
@@ -191,7 +191,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
                 // AggregateKind is not distinguished by visit API, so
                 // record it. (`super_rvalue` handles `_operands`.)
                 self.record(match *kind {
-                    AggregateKind::Array => "AggregateKind::Array",
+                    AggregateKind::Array(_) => "AggregateKind::Array",
                     AggregateKind::Tuple => "AggregateKind::Tuple",
                     AggregateKind::Adt(..) => "AggregateKind::Adt",
                     AggregateKind::Closure(..) => "AggregateKind::Closure",
@@ -297,13 +297,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
         self.super_const_usize(const_usize);
     }
 
-    fn visit_typed_const_val(&mut self,
-                             val: &TypedConstVal<'tcx>,
-                             location: Location) {
-        self.record("TypedConstVal", val);
-        self.super_typed_const_val(val, location);
-    }
-
     fn visit_local_decl(&mut self,
                         local_decl: &LocalDecl<'tcx>) {
         self.record("LocalDecl", local_decl);
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 771a5b7f366a1..c524d8351e003 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -529,7 +529,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
 
             mir::Rvalue::Repeat(ref elem, ref count) => {
                 let elem = self.const_operand(elem, span)?;
-                let size = count.value.as_u64(tcx.sess.target.uint_type);
+                let size = count.as_u64(tcx.sess.target.uint_type);
                 let fields = vec![elem.llval; size as usize];
                 self.const_array(dest_ty, &fields)
             }
@@ -548,7 +548,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                 failure?;
 
                 match *kind {
-                    mir::AggregateKind::Array => {
+                    mir::AggregateKind::Array(_) => {
                         self.const_array(dest_ty, &fields)
                     }
                     mir::AggregateKind::Adt(..) |
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 037c771c97b06..b6af4e52e820b 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -95,7 +95,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
 
             mir::Rvalue::Repeat(ref elem, ref count) => {
                 let tr_elem = self.trans_operand(&bcx, elem);
-                let size = count.value.as_u64(bcx.tcx().sess.target.uint_type);
+                let size = count.as_u64(bcx.tcx().sess.target.uint_type);
                 let size = C_uint(bcx.ccx, size);
                 let base = base::get_dataptr(&bcx, dest.llval);
                 tvec::slice_for_each(&bcx, base, tr_elem.ty, size, |bcx, llslot| {
@@ -435,7 +435,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
             mir::Rvalue::Discriminant(ref lvalue) => {
                 let discr_lvalue = self.trans_lvalue(&bcx, lvalue);
                 let enum_ty = discr_lvalue.ty.to_ty(bcx.tcx());
-                let discr_ty = rvalue.ty(&*self.mir, bcx.tcx()).unwrap();
+                let discr_ty = rvalue.ty(&*self.mir, bcx.tcx());
                 let discr_type = type_of::immediate_type_of(bcx.ccx, discr_ty);
                 let discr = adt::trans_get_discr(&bcx, enum_ty, discr_lvalue.llval,
                                                   discr_lvalue.alignment, Some(discr_type), true);
diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs
index b4647df3f4f0a..ca0ab8f1e8c77 100644
--- a/src/librustc_typeck/check/autoderef.rs
+++ b/src/librustc_typeck/check/autoderef.rs
@@ -54,12 +54,16 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
 
         if self.steps.len() == tcx.sess.recursion_limit.get() {
             // We've reached the recursion limit, error gracefully.
+            let suggested_limit = tcx.sess.recursion_limit.get() * 2;
             struct_span_err!(tcx.sess,
                              self.span,
                              E0055,
                              "reached the recursion limit while auto-dereferencing {:?}",
                              self.cur_ty)
                 .span_label(self.span, &format!("deref recursion limit reached"))
+                .help(&format!(
+                        "consider adding a `#[recursion_limit=\"{}\"]` attribute to your crate",
+                        suggested_limit))
                 .emit();
             return None;
         }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 666e2205b4a26..c7d2f0cd31dc6 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -14,7 +14,7 @@ use ast::{self, Attribute, Name, PatKind, MetaItem};
 use attr::HasAttrs;
 use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
 use syntax_pos::{Span, ExpnId, NO_EXPANSION};
-use errors::DiagnosticBuilder;
+use errors::{DiagnosticBuilder, FatalError};
 use ext::expand::{self, Expansion};
 use ext::hygiene::Mark;
 use fold::{self, Folder};
@@ -695,9 +695,15 @@ impl<'a> ExtCtxt<'a> {
 
     pub fn bt_push(&mut self, ei: ExpnInfo) {
         if self.current_expansion.depth > self.ecfg.recursion_limit {
-            self.span_fatal(ei.call_site,
-                            &format!("recursion limit reached while expanding the macro `{}`",
-                                    ei.callee.name()));
+            let suggested_limit = self.ecfg.recursion_limit * 2;
+            let mut err = self.struct_span_fatal(ei.call_site,
+                &format!("recursion limit reached while expanding the macro `{}`",
+                         ei.callee.name()));
+            err.help(&format!(
+                "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
+                suggested_limit));
+            err.emit();
+            panic!(FatalError);
         }
 
         let mut call_site = ei.call_site;
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index c2b72edb66c6c..7de50430184f6 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -763,6 +763,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
                                            "attribute proc macros are currently unstable",
                                            cfg_fn!(proc_macro))),
 
+    ("proc_macro", Normal, Gated(Stability::Unstable,
+                                 "proc_macro",
+                                 "function-like proc macros are currently unstable",
+                                 cfg_fn!(proc_macro))),
+
     ("rustc_derive_registrar", Normal, Gated(Stability::Unstable,
                                              "rustc_derive_registrar",
                                              "used internally by rustc",
diff --git a/src/libsyntax_ext/proc_macro_impl.rs b/src/libsyntax_ext/proc_macro_impl.rs
index b454628acb1c0..f60e5824db962 100644
--- a/src/libsyntax_ext/proc_macro_impl.rs
+++ b/src/libsyntax_ext/proc_macro_impl.rs
@@ -56,3 +56,38 @@ impl base::AttrProcMacro for AttrProcMacro {
         }
     }
 }
+
+pub struct BangProcMacro {
+    pub inner: fn(TsShim) -> TsShim,
+}
+
+impl base::ProcMacro for BangProcMacro {
+    fn expand<'cx>(&self,
+                   ecx: &'cx mut ExtCtxt,
+                   span: Span,
+                   input: TokenStream)
+                   -> TokenStream {
+        let input = __internal::token_stream_wrap(input);
+
+        let res = __internal::set_parse_sess(&ecx.parse_sess, || {
+            panic::catch_unwind(panic::AssertUnwindSafe(|| (self.inner)(input)))
+        });
+
+        match res {
+            Ok(stream) => __internal::token_stream_inner(stream),
+            Err(e) => {
+                let msg = "proc macro panicked";
+                let mut err = ecx.struct_span_fatal(span, msg);
+                if let Some(s) = e.downcast_ref::<String>() {
+                    err.help(&format!("message: {}", s));
+                }
+                if let Some(s) = e.downcast_ref::<&'static str>() {
+                    err.help(&format!("message: {}", s));
+                }
+
+                err.emit();
+                panic!(FatalError);
+            }
+        }
+    }
+}
diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs
index 325f09a83ddab..9c96ad547e1ae 100644
--- a/src/libsyntax_ext/proc_macro_registrar.rs
+++ b/src/libsyntax_ext/proc_macro_registrar.rs
@@ -27,6 +27,9 @@ use syntax_pos::{Span, DUMMY_SP};
 
 use deriving;
 
+const PROC_MACRO_KINDS: [&'static str; 3] =
+    ["proc_macro_derive", "proc_macro_attribute", "proc_macro"];
+
 struct ProcMacroDerive {
     trait_name: ast::Name,
     function_name: Ident,
@@ -34,14 +37,15 @@ struct ProcMacroDerive {
     attrs: Vec<ast::Name>,
 }
 
-struct AttrProcMacro {
+struct ProcMacroDef {
     function_name: Ident,
     span: Span,
 }
 
 struct CollectProcMacros<'a> {
     derives: Vec<ProcMacroDerive>,
-    attr_macros: Vec<AttrProcMacro>,
+    attr_macros: Vec<ProcMacroDef>,
+    bang_macros: Vec<ProcMacroDef>,
     in_root: bool,
     handler: &'a errors::Handler,
     is_proc_macro_crate: bool,
@@ -58,17 +62,18 @@ pub fn modify(sess: &ParseSess,
     let ecfg = ExpansionConfig::default("proc_macro".to_string());
     let mut cx = ExtCtxt::new(sess, ecfg, resolver);
 
-    let (derives, attr_macros) = {
+    let (derives, attr_macros, bang_macros) = {
         let mut collect = CollectProcMacros {
             derives: Vec::new(),
             attr_macros: Vec::new(),
+            bang_macros: Vec::new(),
             in_root: true,
             handler: handler,
             is_proc_macro_crate: is_proc_macro_crate,
             is_test_crate: is_test_crate,
         };
         visit::walk_crate(&mut collect, &krate);
-        (collect.derives, collect.attr_macros)
+        (collect.derives, collect.attr_macros, collect.bang_macros)
     };
 
     if !is_proc_macro_crate {
@@ -83,7 +88,7 @@ pub fn modify(sess: &ParseSess,
         return krate;
     }
 
-    krate.module.items.push(mk_registrar(&mut cx, &derives, &attr_macros));
+    krate.module.items.push(mk_registrar(&mut cx, &derives, &attr_macros, &bang_macros));
 
     if krate.exported_macros.len() > 0 {
         handler.err("cannot export macro_rules! macros from a `proc-macro` \
@@ -93,6 +98,10 @@ pub fn modify(sess: &ParseSess,
     return krate
 }
 
+fn is_proc_macro_attr(attr: &ast::Attribute) -> bool {
+    PROC_MACRO_KINDS.iter().any(|kind| attr.check_name(kind))
+}
+
 impl<'a> CollectProcMacros<'a> {
     fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) {
         if self.is_proc_macro_crate &&
@@ -196,12 +205,12 @@ impl<'a> CollectProcMacros<'a> {
     fn collect_attr_proc_macro(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) {
         if let Some(_) = attr.meta_item_list() {
             self.handler.span_err(attr.span, "`#[proc_macro_attribute]` attribute
-                cannot contain any meta items");
+                does not take any arguments");
             return;
         }
 
         if self.in_root && item.vis == ast::Visibility::Public {
-            self.attr_macros.push(AttrProcMacro {
+            self.attr_macros.push(ProcMacroDef {
                 span: item.span,
                 function_name: item.ident,
             });
@@ -215,6 +224,29 @@ impl<'a> CollectProcMacros<'a> {
             self.handler.span_err(item.span, msg);
         }
     }
+
+    fn collect_bang_proc_macro(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) {
+        if let Some(_) = attr.meta_item_list() {
+            self.handler.span_err(attr.span, "`#[proc_macro]` attribute
+                does not take any arguments");
+            return;
+        }
+
+        if self.in_root && item.vis == ast::Visibility::Public {
+            self.bang_macros.push(ProcMacroDef {
+                span: item.span,
+                function_name: item.ident,
+            });
+        } else {
+            let msg = if !self.in_root {
+                "functions tagged with `#[proc_macro]` must \
+                 currently reside in the root of the crate"
+            } else {
+                "functions tagged with `#[proc_macro]` must be `pub`"
+            };
+            self.handler.span_err(item.span, msg);
+        }
+    }
 }
 
 impl<'a> Visitor<'a> for CollectProcMacros<'a> {
@@ -232,7 +264,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
         let mut found_attr: Option<&'a ast::Attribute> = None;
 
         for attr in &item.attrs {
-            if attr.check_name("proc_macro_derive") || attr.check_name("proc_macro_attribute") {
+            if is_proc_macro_attr(&attr) {
                 if let Some(prev_attr) = found_attr {
                     let msg = if attr.name() == prev_attr.name() {
                         format!("Only one `#[{}]` attribute is allowed on any given function",
@@ -285,6 +317,8 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
             self.collect_custom_derive(item, attr);
         } else if attr.check_name("proc_macro_attribute") {
             self.collect_attr_proc_macro(item, attr);
+        } else if attr.check_name("proc_macro") {
+            self.collect_bang_proc_macro(item, attr);
         };
 
         visit::walk_item(self, item);
@@ -320,7 +354,8 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
 //      }
 fn mk_registrar(cx: &mut ExtCtxt,
                 custom_derives: &[ProcMacroDerive],
-                custom_attrs: &[AttrProcMacro]) -> P<ast::Item> {
+                custom_attrs: &[ProcMacroDef],
+                custom_macros: &[ProcMacroDef]) -> P<ast::Item> {
     let eid = cx.codemap().record_expansion(ExpnInfo {
         call_site: DUMMY_SP,
         callee: NameAndSpan {
@@ -342,6 +377,7 @@ fn mk_registrar(cx: &mut ExtCtxt,
     let registrar = Ident::from_str("registrar");
     let register_custom_derive = Ident::from_str("register_custom_derive");
     let register_attr_proc_macro = Ident::from_str("register_attr_proc_macro");
+    let register_bang_proc_macro = Ident::from_str("register_bang_proc_macro");
 
     let mut stmts = custom_derives.iter().map(|cd| {
         let path = cx.path_global(cd.span, vec![cd.function_name]);
@@ -371,6 +407,18 @@ fn mk_registrar(cx: &mut ExtCtxt,
                                   vec![registrar, name, cx.expr_path(path)]))
     }));
 
+    stmts.extend(custom_macros.iter().map(|cm| {
+        let name = cx.expr_str(cm.span, cm.function_name.name);
+        let path = cx.path_global(cm.span, vec![cm.function_name]);
+        let registrar = cx.expr_ident(cm.span, registrar);
+
+        let ufcs_path = cx.path(span,
+                                vec![proc_macro, __internal, registry, register_bang_proc_macro]);
+
+        cx.stmt_expr(cx.expr_call(span, cx.expr_path(ufcs_path),
+                                  vec![registrar, name, cx.expr_path(path)]))
+    }));
+
     let path = cx.path(span, vec![proc_macro, __internal, registry]);
     let registrar_path = cx.ty_path(path);
     let arg_ty = cx.ty_rptr(span, registrar_path, None, ast::Mutability::Mutable);
diff --git a/src/llvm b/src/llvm
index ceb177eeefa7d..50ab09fb43f03 160000
--- a/src/llvm
+++ b/src/llvm
@@ -1 +1 @@
-Subproject commit ceb177eeefa7d67ca29230d2e7e8584f97d4fdad
+Subproject commit 50ab09fb43f038e4f824eea6cb278f560d3e8621
diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger
index ab36e9a2c2b20..57f37ea050c1b 100644
--- a/src/rustllvm/llvm-auto-clean-trigger
+++ b/src/rustllvm/llvm-auto-clean-trigger
@@ -1,4 +1,4 @@
 # If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
 # The actual contents of this file do not matter, but to trigger a change on the
 # build bots then the contents should be changed so git updates the mtime.
-2017-02-15
+2017-03-02
diff --git a/src/test/codegen/lifetime_start_end.rs b/src/test/codegen/lifetime_start_end.rs
index e3b35cf355250..5c1f1f8f2bb20 100644
--- a/src/test/codegen/lifetime_start_end.rs
+++ b/src/test/codegen/lifetime_start_end.rs
@@ -11,11 +11,9 @@
 // compile-flags: -O -C no-prepopulate-passes
 
 #![crate_type = "lib"]
-#![feature(rustc_attrs)]
 
 // CHECK-LABEL: @test
 #[no_mangle]
-#[rustc_mir] // FIXME #27840 MIR has different codegen.
 pub fn test() {
     let a = 0;
     &a; // keep variable in an alloca
@@ -33,11 +31,11 @@ pub fn test() {
 // CHECK: [[S__5:%[0-9]+]] = bitcast %"core::option::Option<i32>"* %_5 to i8*
 // CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S__5]])
 
-// CHECK: [[E__5:%[0-9]+]] = bitcast %"core::option::Option<i32>"* %_5 to i8*
-// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E__5]])
-
 // CHECK: [[E_b:%[0-9]+]] = bitcast %"core::option::Option<i32>"** %b to i8*
 // CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E_b]])
+
+// CHECK: [[E__5:%[0-9]+]] = bitcast %"core::option::Option<i32>"* %_5 to i8*
+// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E__5]])
     }
 
     let c = 1;
diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/bang_proc_macro.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/bang_proc_macro.rs
new file mode 100644
index 0000000000000..89ac11b309d75
--- /dev/null
+++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/bang_proc_macro.rs
@@ -0,0 +1,23 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// force-host
+// no-prefer-dynamic
+#![feature(proc_macro)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn bang_proc_macro(input: TokenStream) -> TokenStream {
+    input
+}
diff --git a/src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs b/src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs
new file mode 100644
index 0000000000000..7ecc685357ee6
--- /dev/null
+++ b/src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs
@@ -0,0 +1,21 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:bang_proc_macro.rs
+
+#![feature(proc_macro)]
+
+#[macro_use]
+extern crate bang_proc_macro;
+
+fn main() {
+    bang_proc_macro!(println!("Hello, world!"));
+    //~^ ERROR: procedural macros cannot be imported with `#[macro_use]`
+}
diff --git a/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs b/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs
index eac0be6f84874..e0066dd43be89 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs
@@ -11,6 +11,7 @@
 // aux-build:derive-foo.rs
 // aux-build:derive-clona.rs
 // aux-build:attr_proc_macro.rs
+// aux-build:bang_proc_macro.rs
 
 #![feature(proc_macro)]
 
@@ -19,13 +20,19 @@ extern crate derive_foo;
 #[macro_use]
 extern crate derive_clona;
 extern crate attr_proc_macro;
+extern crate bang_proc_macro;
 
 use attr_proc_macro::attr_proc_macro;
+use bang_proc_macro::bang_proc_macro;
 
 macro_rules! FooWithLongNam {
     () => {}
 }
 
+macro_rules! attr_proc_mac {
+    () => {}
+}
+
 #[derive(FooWithLongNan)]
 //~^ ERROR cannot find derive macro `FooWithLongNan` in this scope
 //~^^ HELP did you mean `FooWithLongName`?
@@ -61,7 +68,12 @@ fn main() {
 
     attr_proc_macra!();
     //~^ ERROR cannot find macro `attr_proc_macra!` in this scope
+    //~^^ HELP did you mean `attr_proc_mac!`?
 
     Dlona!();
     //~^ ERROR cannot find macro `Dlona!` in this scope
+
+    bang_proc_macrp!();
+    //~^ ERROR cannot find macro `bang_proc_macrp!` in this scope
+    //~^^ HELP did you mean `bang_proc_macro!`?
 }
diff --git a/src/test/compile-fail/recursion_limit.rs b/src/test/compile-fail/recursion_limit.rs
deleted file mode 100644
index 226a6d57ddbf0..0000000000000
--- a/src/test/compile-fail/recursion_limit.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Test that the recursion limit can be changed. In this case, we have
-// deeply nested types that will fail the `Send` check by overflow
-// when the recursion limit is set very low.
-
-#![allow(dead_code)]
-#![recursion_limit="10"]
-
-macro_rules! link {
-    ($id:ident, $t:ty) => {
-        enum $id { $id($t) }
-    }
-}
-
-link! { A, B }
-link! { B, C }
-link! { C, D }
-link! { D, E }
-link! { E, F }
-link! { F, G }
-link! { G, H }
-link! { H, I }
-link! { I, J }
-link! { J, K }
-link! { K, L }
-link! { L, M }
-link! { M, N }
-
-enum N { N(usize) }
-
-fn is_send<T:Send>() { }
-
-fn main() {
-    is_send::<A>();
-    //~^ ERROR overflow evaluating
-    //~| NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
-    //~| NOTE required because it appears within the type `A`
-    //~| NOTE required because it appears within the type `B`
-    //~| NOTE required because it appears within the type `C`
-    //~| NOTE required because it appears within the type `D`
-    //~| NOTE required because it appears within the type `E`
-    //~| NOTE required because it appears within the type `F`
-    //~| NOTE required because it appears within the type `G`
-    //~| NOTE required because it appears within the type `H`
-    //~| NOTE required because it appears within the type `I`
-    //~| NOTE required because it appears within the type `J`
-    //~| NOTE required by `is_send`
-}
diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs
new file mode 100644
index 0000000000000..9c924a23903f9
--- /dev/null
+++ b/src/test/mir-opt/basic_assignment.rs
@@ -0,0 +1,85 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// this tests move up progration, which is not yet implemented
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// check that codegen of assignment expressions is sane. Assignments
+// tend to be absent in simple code, so subtle breakage in them can
+// leave a quite hard-to-find trail of destruction.
+
+fn main() {
+    let nodrop_x = false;
+    let nodrop_y;
+
+    nodrop_y = nodrop_x;
+
+    let drop_x : Option<Box<u32>> = None;
+    let drop_y;
+
+    drop_y = drop_x;
+}
+
+// END RUST SOURCE
+// START rustc.node4.SimplifyCfg.initial-after.mir
+//     bb0: {
+//         StorageLive(_1);
+//         _1 = const false;
+//         StorageLive(_2);
+//         StorageLive(_3);
+//         _3 = _1;
+//         _2 = _3;
+//         StorageDead(_3);
+//         StorageLive(_4);
+//         _4 = std::option::Option<std::boxed::Box<u32>>::None;
+//         StorageLive(_6);
+//         StorageLive(_7);
+//         _7 = _4;
+//         replace(_6 <- _7) -> [return: bb5, unwind: bb4];
+//     }
+//     bb1: {
+//         resume;
+//     }
+//     bb2: {
+//         drop(_4) -> bb1;
+//     }
+//     bb3: {
+//         drop(_6) -> bb2;
+//     }
+//     bb4: {
+//         drop(_7) -> bb3;
+//     }
+//     bb5: {
+//         drop(_7) -> [return: bb6, unwind: bb3];
+//     }
+//     bb6: {
+//         StorageDead(_7);
+//         _0 = ();
+//         drop(_6) -> [return: bb7, unwind: bb2];
+//     }
+//     bb7: {
+//         StorageDead(_6);
+//         drop(_4) -> bb8;
+//     }
+//     bb8: {
+//         StorageDead(_4);
+//         StorageDead(_2);
+//         StorageDead(_1);
+//         return;
+//     }
+// END rustc.node4.SimplifyCfg.initial-after.mir
diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs
new file mode 100644
index 0000000000000..d1e515c4f2b15
--- /dev/null
+++ b/src/test/mir-opt/issue-38669.rs
@@ -0,0 +1,52 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// check that we don't StorageDead booleans before they are used
+
+fn main() {
+    let mut should_break = false;
+    loop {
+        if should_break {
+            break;
+        }
+        should_break = true;
+    }
+}
+
+// END RUST SOURCE
+// START rustc.node4.SimplifyCfg.initial-after.mir
+//     bb0: {
+//         StorageLive(_1);
+//         _1 = const false;
+//         goto -> bb1;
+//     }
+//
+//     bb1: {
+//         StorageLive(_4);
+//         _4 = _1;
+//         switchInt(_4) -> [0: bb3, otherwise: bb2];
+//     }
+//
+//     bb2: {
+//         StorageLive(_6);
+//         _0 = ();
+//         StorageDead(_4);
+//         StorageDead(_1);
+//         return;
+//     }
+//
+//     bb3: {
+//         _3 = ();
+//         StorageDead(_4);
+//         _1 = const true;
+//         _2 = ();
+//         goto -> bb1;
+//     }
+// END rustc.node4.SimplifyCfg.initial-after.mir
diff --git a/src/test/mir-opt/storage_ranges.rs b/src/test/mir-opt/storage_ranges.rs
index 933bfa8df2ec2..3fbd1a36f2f16 100644
--- a/src/test/mir-opt/storage_ranges.rs
+++ b/src/test/mir-opt/storage_ranges.rs
@@ -28,16 +28,15 @@ fn main() {
 //         StorageLive(_5);
 //         _5 = _1;
 //         _4 = std::option::Option<i32>::Some(_5,);
-//         _3 = &_4;
 //         StorageDead(_5);
+//         _3 = &_4;
 //         _2 = ();
-//         StorageDead(_4);
 //         StorageDead(_3);
+//         StorageDead(_4);
 //         StorageLive(_6);
 //         _6 = const 1i32;
 //         _0 = ();
 //         StorageDead(_6);
 //         StorageDead(_1);
-//         return;
-//     }
+//      }
 // END rustc.node4.TypeckMir.before.mir
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/bang-macro.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/bang-macro.rs
new file mode 100644
index 0000000000000..122a47aff7198
--- /dev/null
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/bang-macro.rs
@@ -0,0 +1,26 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+#![feature(proc_macro)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn rewrite(input: TokenStream) -> TokenStream {
+    let input = input.to_string();
+
+    assert_eq!(input, r#""Hello, world!""#);
+
+    r#""NOT Hello, world!""#.parse().unwrap()
+}
diff --git a/src/test/run-pass-fulldeps/proc-macro/bang-macro.rs b/src/test/run-pass-fulldeps/proc-macro/bang-macro.rs
new file mode 100644
index 0000000000000..531bd0dd3569d
--- /dev/null
+++ b/src/test/run-pass-fulldeps/proc-macro/bang-macro.rs
@@ -0,0 +1,20 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:bang-macro.rs
+
+#![feature(proc_macro)]
+
+extern crate bang_macro;
+use bang_macro::rewrite;
+
+fn main() {
+    assert_eq!(rewrite!("Hello, world!"), "NOT Hello, world!");
+}
diff --git a/src/test/run-pass/mir_drop_order.rs b/src/test/run-pass/mir_drop_order.rs
new file mode 100644
index 0000000000000..e7da43597f169
--- /dev/null
+++ b/src/test/run-pass/mir_drop_order.rs
@@ -0,0 +1,55 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::cell::RefCell;
+use std::panic;
+
+pub struct DropLogger<'a> {
+    id: usize,
+    log: &'a panic::AssertUnwindSafe<RefCell<Vec<usize>>>
+}
+
+impl<'a> Drop for DropLogger<'a> {
+    fn drop(&mut self) {
+        self.log.0.borrow_mut().push(self.id);
+    }
+}
+
+struct InjectedFailure;
+
+#[allow(unreachable_code)]
+fn main() {
+    let log = panic::AssertUnwindSafe(RefCell::new(vec![]));
+    let d = |id| DropLogger { id: id, log: &log };
+    let get = || -> Vec<_> {
+        let mut m = log.0.borrow_mut();
+        let n = m.drain(..);
+        n.collect()
+    };
+
+    {
+        let _x = (d(0), &d(1), d(2), &d(3));
+        // all borrows are extended - nothing has been dropped yet
+        assert_eq!(get(), vec![]);
+    }
+    // in a let-statement, extended lvalues are dropped
+    // *after* the let result (tho they have the same scope
+    // as far as scope-based borrowck goes).
+    assert_eq!(get(), vec![0, 2, 3, 1]);
+
+    let _ = std::panic::catch_unwind(|| {
+        (d(4), &d(5), d(6), &d(7), panic!(InjectedFailure));
+    });
+
+    // here, the temporaries (5/7) live until the end of the
+    // containing statement, which is destroyed after the operands
+    // (4/6) on a panic.
+    assert_eq!(get(), vec![6, 4, 7, 5]);
+}
diff --git a/src/test/ui/did_you_mean/recursion_limit.rs b/src/test/ui/did_you_mean/recursion_limit.rs
new file mode 100644
index 0000000000000..becb81b1fff7e
--- /dev/null
+++ b/src/test/ui/did_you_mean/recursion_limit.rs
@@ -0,0 +1,45 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the recursion limit can be changed and that the compiler
+// suggests a fix. In this case, we have deeply nested types that will
+// fail the `Send` check by overflow when the recursion limit is set
+// very low.
+
+#![allow(dead_code)]
+#![recursion_limit="10"]
+
+macro_rules! link {
+    ($id:ident, $t:ty) => {
+        enum $id { $id($t) }
+    }
+}
+
+link! { A, B }
+link! { B, C }
+link! { C, D }
+link! { D, E }
+link! { E, F }
+link! { F, G }
+link! { G, H }
+link! { H, I }
+link! { I, J }
+link! { J, K }
+link! { K, L }
+link! { L, M }
+link! { M, N }
+
+enum N { N(usize) }
+
+fn is_send<T:Send>() { }
+
+fn main() {
+    is_send::<A>();
+}
diff --git a/src/test/ui/did_you_mean/recursion_limit.stderr b/src/test/ui/did_you_mean/recursion_limit.stderr
new file mode 100644
index 0000000000000..d157c5de6c7f5
--- /dev/null
+++ b/src/test/ui/did_you_mean/recursion_limit.stderr
@@ -0,0 +1,21 @@
+error[E0275]: overflow evaluating the requirement `K: std::marker::Send`
+  --> $DIR/recursion_limit.rs:44:5
+   |
+44 |     is_send::<A>();
+   |     ^^^^^^^^^^^^
+   |
+   = help: consider adding a `#![recursion_limit="20"]` attribute to your crate
+   = note: required because it appears within the type `J`
+   = note: required because it appears within the type `I`
+   = note: required because it appears within the type `H`
+   = note: required because it appears within the type `G`
+   = note: required because it appears within the type `F`
+   = note: required because it appears within the type `E`
+   = note: required because it appears within the type `D`
+   = note: required because it appears within the type `C`
+   = note: required because it appears within the type `B`
+   = note: required because it appears within the type `A`
+   = note: required by `is_send`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/did_you_mean/recursion_limit_deref.rs b/src/test/ui/did_you_mean/recursion_limit_deref.rs
new file mode 100644
index 0000000000000..ebc56c94adf84
--- /dev/null
+++ b/src/test/ui/did_you_mean/recursion_limit_deref.rs
@@ -0,0 +1,62 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the recursion limit can be changed and that the compiler
+// suggests a fix. In this case, we have a long chain of Deref impls
+// which will cause an overflow during the autoderef loop.
+
+#![allow(dead_code)]
+#![recursion_limit="10"]
+
+macro_rules! link {
+    ($outer:ident, $inner:ident) => {
+        struct $outer($inner);
+
+        impl $outer {
+            fn new() -> $outer {
+                $outer($inner::new())
+            }
+        }
+
+        impl std::ops::Deref for $outer {
+            type Target = $inner;
+
+            fn deref(&self) -> &$inner {
+                &self.0
+            }
+        }
+    }
+}
+
+struct Bottom;
+impl Bottom {
+    fn new() -> Bottom {
+        Bottom
+    }
+}
+
+link!(Top, A);
+link!(A, B);
+link!(B, C);
+link!(C, D);
+link!(D, E);
+link!(E, F);
+link!(F, G);
+link!(G, H);
+link!(H, I);
+link!(I, J);
+link!(J, K);
+link!(K, Bottom);
+
+fn main() {
+    let t = Top::new();
+    let x: &Bottom = &t;
+}
+
diff --git a/src/test/ui/did_you_mean/recursion_limit_deref.stderr b/src/test/ui/did_you_mean/recursion_limit_deref.stderr
new file mode 100644
index 0000000000000..57b28d0373622
--- /dev/null
+++ b/src/test/ui/did_you_mean/recursion_limit_deref.stderr
@@ -0,0 +1,23 @@
+error[E0055]: reached the recursion limit while auto-dereferencing I
+  --> $DIR/recursion_limit_deref.rs:60:22
+   |
+60 |     let x: &Bottom = &t;
+   |                      ^^ deref recursion limit reached
+   |
+   = help: consider adding a `#[recursion_limit="20"]` attribute to your crate
+
+error[E0055]: reached the recursion limit while auto-dereferencing I
+  |
+  = help: consider adding a `#[recursion_limit="20"]` attribute to your crate
+
+error[E0308]: mismatched types
+  --> $DIR/recursion_limit_deref.rs:60:22
+   |
+60 |     let x: &Bottom = &t;
+   |                      ^^ expected struct `Bottom`, found struct `Top`
+   |
+   = note: expected type `&Bottom`
+              found type `&Top`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/did_you_mean/recursion_limit_macro.rs b/src/test/ui/did_you_mean/recursion_limit_macro.rs
new file mode 100644
index 0000000000000..9fb82b730c9b3
--- /dev/null
+++ b/src/test/ui/did_you_mean/recursion_limit_macro.rs
@@ -0,0 +1,26 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the recursion limit can be changed and that the compiler
+// suggests a fix. In this case, we have a recursing macro that will
+// overflow if the number of arguments surpasses the recursion limit.
+
+#![allow(dead_code)]
+#![recursion_limit="10"]
+
+macro_rules! recurse {
+    () => { };
+    ($t:tt $($tail:tt)*) => { recurse!($($tail)*) };
+}
+
+fn main() {
+    recurse!(0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9);
+}
+
diff --git a/src/test/ui/did_you_mean/recursion_limit_macro.stderr b/src/test/ui/did_you_mean/recursion_limit_macro.stderr
new file mode 100644
index 0000000000000..19aac1f77e7c1
--- /dev/null
+++ b/src/test/ui/did_you_mean/recursion_limit_macro.stderr
@@ -0,0 +1,11 @@
+error: recursion limit reached while expanding the macro `recurse`
+  --> $DIR/recursion_limit_macro.rs:20:31
+   |
+20 |     ($t:tt $($tail:tt)*) => { recurse!($($tail)*) };
+   |                               ^^^^^^^^^^^^^^^^^^^
+...
+24 |     recurse!(0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9);
+   |     -------------------------------------------------- in this macro invocation
+   |
+   = help: consider adding a `#![recursion_limit="20"]` attribute to your crate
+