about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTim Neumann <mail@timnn.me>2017-04-12 14:45:47 +0200
committerGitHub <noreply@github.com>2017-04-12 14:45:47 +0200
commit1dd9801fa53bf77aa903d2b705959738b70729fc (patch)
tree9f685511a6ac5bcf506730a3d5cabe38554ab9af
parent092f19ac99c244236e31ea34eea9acdd557a79ae (diff)
parent540a069761c1184ee2998f23a24b76c97c274043 (diff)
downloadrust-1dd9801fa53bf77aa903d2b705959738b70729fc.tar.gz
rust-1dd9801fa53bf77aa903d2b705959738b70729fc.zip
Rollup merge of #41232 - arielb1:mir-rvalues, r=eddyb
move rvalue checking to MIR
-rw-r--r--src/librustc/ich/impls_mir.rs3
-rw-r--r--src/librustc/mir/mod.rs40
-rw-r--r--src/librustc/mir/visit.rs5
-rw-r--r--src/librustc_borrowck/borrowck/mir/elaborate_drops.rs6
-rw-r--r--src/librustc_driver/driver.rs8
-rw-r--r--src/librustc_mir/build/expr/as_lvalue.rs3
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs14
-rw-r--r--src/librustc_mir/build/expr/as_temp.rs2
-rw-r--r--src/librustc_mir/build/expr/stmt.rs2
-rw-r--r--src/librustc_mir/build/matches/mod.rs3
-rw-r--r--src/librustc_mir/build/matches/test.rs13
-rw-r--r--src/librustc_mir/build/misc.rs6
-rw-r--r--src/librustc_mir/build/mod.rs12
-rw-r--r--src/librustc_mir/diagnostics.rs33
-rw-r--r--src/librustc_mir/shim.rs23
-rw-r--r--src/librustc_mir/transform/inline.rs15
-rw-r--r--src/librustc_mir/transform/promote_consts.rs6
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs2
-rw-r--r--src/librustc_mir/transform/type_check.rs52
-rw-r--r--src/librustc_mir/util/elaborate_drops.rs2
-rw-r--r--src/librustc_mir/util/patch.rs5
-rw-r--r--src/librustc_mir/util/pretty.rs4
-rw-r--r--src/librustc_passes/diagnostics.rs33
-rw-r--r--src/librustc_passes/lib.rs1
-rw-r--r--src/librustc_passes/rvalues.rs103
-rw-r--r--src/librustc_trans/debuginfo/create_scope_map.rs2
-rw-r--r--src/librustc_trans/mir/mod.rs5
-rw-r--r--src/test/compile-fail/issue-41139.rs18
28 files changed, 197 insertions, 224 deletions
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index 401f7e1921a..3ff8ffb3505 100644
--- a/src/librustc/ich/impls_mir.rs
+++ b/src/librustc/ich/impls_mir.rs
@@ -22,7 +22,8 @@ impl_stable_hash_for!(struct mir::SourceInfo { span, scope });
 impl_stable_hash_for!(enum mir::Mutability { Mut, Not });
 impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut });
 impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer });
-impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info });
+impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info,
+is_user_variable});
 impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref });
 impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup });
 impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info, kind });
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index aea4684e526..9ff64b295b7 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -197,10 +197,10 @@ impl<'tcx> Mir<'tcx> {
     pub fn temps_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
         (self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
             let local = Local::new(index);
-            if self.local_decls[local].source_info.is_none() {
-                Some(local)
-            } else {
+            if self.local_decls[local].is_user_variable {
                 None
+            } else {
+                Some(local)
             }
         })
     }
@@ -210,10 +210,10 @@ impl<'tcx> Mir<'tcx> {
     pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
         (self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
             let local = Local::new(index);
-            if self.local_decls[local].source_info.is_none() {
-                None
-            } else {
+            if self.local_decls[local].is_user_variable {
                 Some(local)
+            } else {
+                None
             }
         })
     }
@@ -370,6 +370,9 @@ pub struct LocalDecl<'tcx> {
     /// Temporaries and the return pointer are always mutable.
     pub mutability: Mutability,
 
+    /// True if this corresponds to a user-declared local variable.
+    pub is_user_variable: bool,
+
     /// Type of this local.
     pub ty: Ty<'tcx>,
 
@@ -379,24 +382,23 @@ pub struct LocalDecl<'tcx> {
     /// to generate better debuginfo.
     pub name: Option<Name>,
 
-    /// For user-declared variables, stores their source information.
-    ///
-    /// For temporaries, this is `None`.
-    ///
-    /// This is the primary way to differentiate between user-declared
-    /// variables and compiler-generated temporaries.
-    pub source_info: Option<SourceInfo>,
+    /// Source info of the local.
+    pub source_info: SourceInfo,
 }
 
 impl<'tcx> LocalDecl<'tcx> {
     /// Create a new `LocalDecl` for a temporary.
     #[inline]
-    pub fn new_temp(ty: Ty<'tcx>) -> Self {
+    pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self {
         LocalDecl {
             mutability: Mutability::Mut,
             ty: ty,
             name: None,
-            source_info: None,
+            source_info: SourceInfo {
+                span: span,
+                scope: ARGUMENT_VISIBILITY_SCOPE
+            },
+            is_user_variable: false
         }
     }
 
@@ -404,12 +406,16 @@ impl<'tcx> LocalDecl<'tcx> {
     ///
     /// This must be inserted into the `local_decls` list as the first local.
     #[inline]
-    pub fn new_return_pointer(return_ty: Ty) -> LocalDecl {
+    pub fn new_return_pointer(return_ty: Ty, span: Span) -> LocalDecl {
         LocalDecl {
             mutability: Mutability::Mut,
             ty: return_ty,
-            source_info: None,
+            source_info: SourceInfo {
+                span: span,
+                scope: ARGUMENT_VISIBILITY_SCOPE
+            },
             name: None,     // FIXME maybe we do want some name here?
+            is_user_variable: false
         }
     }
 }
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 733ad36de90..83963de8b00 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -630,12 +630,11 @@ macro_rules! make_mir_visitor {
                     ref $($mutability)* ty,
                     name: _,
                     ref $($mutability)* source_info,
+                    is_user_variable: _,
                 } = *local_decl;
 
                 self.visit_ty(ty);
-                if let Some(ref $($mutability)* info) = *source_info {
-                    self.visit_source_info(info);
-                }
+                self.visit_source_info(source_info);
             }
 
             fn super_visibility_scope(&mut self,
diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
index 713e6566662..ca313622a3a 100644
--- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
+++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
@@ -307,12 +307,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
         data
     }
 
-    fn create_drop_flag(&mut self, index: MovePathIndex) {
+    fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) {
         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)
+            patch.new_temp(tcx.types.bool, span)
         });
     }
 
@@ -374,7 +374,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                 debug!("collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}",
                        child, location, path, (maybe_live, maybe_dead));
                 if maybe_live && maybe_dead {
-                    self.create_drop_flag(child)
+                    self.create_drop_flag(child, terminator.source_info.span)
                 }
             });
         }
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 21888ba94b3..20ae561431b 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -35,7 +35,7 @@ use rustc_typeck as typeck;
 use rustc_privacy;
 use rustc_plugin::registry::Registry;
 use rustc_plugin as plugin;
-use rustc_passes::{ast_validation, no_asm, loops, consts, rvalues,
+use rustc_passes::{ast_validation, no_asm, loops, consts,
                    static_recursion, hir_stats, mir_stats};
 use rustc_const_eval::check_match;
 use super::Compilation;
@@ -959,10 +959,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
              || middle::liveness::check_crate(tcx));
 
         time(time_passes,
-             "rvalue checking",
-             || rvalues::check_crate(tcx));
-
-        time(time_passes,
              "MIR dump",
              || mir::mir_map::build_mir_for_crate(tcx));
 
@@ -977,8 +973,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
             // in stage 4 below.
             passes.push_hook(box mir::transform::dump_mir::DumpMir);
             passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("initial"));
-            passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants);
             passes.push_pass(box mir::transform::type_check::TypeckMir);
+            passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants);
             passes.push_pass(
                 box mir::transform::simplify_branches::SimplifyBranches::new("initial"));
             passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("qualify-consts"));
diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs
index 1cd9a1b25ba..df2841a6682 100644
--- a/src/librustc_mir/build/expr/as_lvalue.rs
+++ b/src/librustc_mir/build/expr/as_lvalue.rs
@@ -62,7 +62,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let idx = unpack!(block = this.as_operand(block, None, index));
 
                 // bounds check:
-                let (len, lt) = (this.temp(usize_ty.clone()), this.temp(bool_ty));
+                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
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 6694107a8d4..fb547332c5f 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -82,7 +82,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     let bool_ty = this.hir.bool_ty();
 
                     let minval = this.minval_literal(expr_span, expr.ty);
-                    let is_min = this.temp(bool_ty);
+                    let is_min = this.temp(bool_ty, expr_span);
 
                     this.cfg.push_assign(block, source_info, &is_min,
                                          Rvalue::BinaryOp(BinOp::Eq, arg.clone(), minval));
@@ -95,7 +95,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
             ExprKind::Box { value, value_extents } => {
                 let value = this.hir.mirror(value);
-                let result = this.temp(expr.ty);
+                let result = this.temp(expr.ty, expr_span);
                 // to start, malloc some memory of suitable type (thus far, uninitialized):
                 this.cfg.push_assign(block, source_info, &result, Rvalue::Box(value.ty));
                 this.in_scope(value_extents, block, |this| {
@@ -260,7 +260,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         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], false);
-            let result_value = self.temp(result_tup);
+            let result_value = self.temp(result_tup, span);
 
             self.cfg.push_assign(block, source_info,
                                  &result_value, Rvalue::CheckedBinaryOp(op,
@@ -301,7 +301,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 };
 
                 // Check for / 0
-                let is_zero = self.temp(bool_ty);
+                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.clone(), zero));
@@ -315,9 +315,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     let neg_1 = self.neg_1_literal(span, ty);
                     let min = self.minval_literal(span, ty);
 
-                    let is_neg_1 = self.temp(bool_ty);
-                    let is_min   = self.temp(bool_ty);
-                    let of       = self.temp(bool_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);
 
                     // this does (rhs == -1) & (lhs == MIN). It could short-circuit instead
 
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index 42d9ab4d2bf..e4598b41438 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -44,8 +44,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         }
 
         let expr_ty = expr.ty.clone();
-        let temp = this.temp(expr_ty.clone());
         let expr_span = expr.span;
+        let temp = this.temp(expr_ty.clone(), expr_span);
         let source_info = this.source_info(expr_span);
 
         if expr.temp_lifetime_was_shrunk && this.hir.needs_drop(expr_ty) {
diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs
index 7336da654c1..c03432312b0 100644
--- a/src/librustc_mir/build/expr/stmt.rs
+++ b/src/librustc_mir/build/expr/stmt.rs
@@ -138,7 +138,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
             _ => {
                 let expr_ty = expr.ty;
-                let temp = this.temp(expr.ty.clone());
+                let temp = this.temp(expr.ty.clone(), expr_span);
                 unpack!(block = this.into(&temp, block, expr));
                 unpack!(block = this.build_drop(block, expr_span, temp, expr_ty));
                 block.unit()
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 705eb1f5660..ddeec1fe6d0 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -710,7 +710,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             mutability: mutability,
             ty: var_ty.clone(),
             name: Some(name),
-            source_info: Some(source_info),
+            source_info: source_info,
+            is_user_variable: true,
         });
         self.var_indices.insert(var_id, var);
 
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index f4fdf8ade90..5fece4d6a5d 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -210,7 +210,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
                        num_enum_variants, values, variants);
                 let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
-                let discr = self.temp(discr_ty);
+                let discr = self.temp(discr_ty, test.span);
                 self.cfg.push_assign(block, source_info, &discr,
                                      Rvalue::Discriminant(lvalue.clone()));
                 assert_eq!(values.len() + 1, targets.len());
@@ -270,7 +270,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     if let ty::TyRef(region, mt) = ty.sty {
                         if let ty::TyArray(_, _) = mt.ty.sty {
                             ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8));
-                            let val_slice = self.temp(ty);
+                            let val_slice = self.temp(ty, test.span);
                             self.cfg.push_assign(block, source_info, &val_slice,
                                                  Rvalue::Cast(CastKind::Unsize, val, ty));
                             val = Operand::Consume(val_slice);
@@ -285,7 +285,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         value: value.clone()
                     });
 
-                    let slice = self.temp(ty);
+                    let slice = self.temp(ty, test.span);
                     self.cfg.push_assign(block, source_info, &slice,
                                          Rvalue::Cast(CastKind::Unsize, array, ty));
                     Operand::Consume(slice)
@@ -304,7 +304,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]);
 
                     let bool_ty = self.hir.bool_ty();
-                    let eq_result = self.temp(bool_ty);
+                    let eq_result = self.temp(bool_ty, test.span);
                     let eq_block = self.cfg.start_new_block();
                     let cleanup = self.diverge_cleanup();
                     self.cfg.terminate(block, source_info, TerminatorKind::Call {
@@ -349,7 +349,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
             TestKind::Len { len, op } => {
                 let (usize_ty, bool_ty) = (self.hir.usize_ty(), self.hir.bool_ty());
-                let (actual, result) = (self.temp(usize_ty), self.temp(bool_ty));
+                let (actual, result) = (self.temp(usize_ty, test.span),
+                                        self.temp(bool_ty, test.span));
 
                 // actual = len(lvalue)
                 self.cfg.push_assign(block, source_info,
@@ -383,7 +384,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                left: Operand<'tcx>,
                right: Operand<'tcx>) -> BasicBlock {
         let bool_ty = self.hir.bool_ty();
-        let result = self.temp(bool_ty);
+        let result = self.temp(bool_ty, span);
 
         // result = op(left, right)
         let source_info = self.source_info(span);
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index 99aa5cb0fa8..35a8b245f2b 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -27,8 +27,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     ///
     /// NB: **No cleanup is scheduled for this temporary.** You should
     /// call `schedule_drop` once the temporary is initialized.
-    pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> {
-        let temp = self.local_decls.push(LocalDecl::new_temp(ty));
+    pub fn temp(&mut self, ty: Ty<'tcx>, span: Span) -> Lvalue<'tcx> {
+        let temp = self.local_decls.push(LocalDecl::new_temp(ty, span));
         let lvalue = Lvalue::Local(temp);
         debug!("temp: created temp {:?} with type {:?}",
                lvalue, self.local_decls[temp].ty);
@@ -106,7 +106,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                       value: u64)
                       -> Lvalue<'tcx> {
         let usize_ty = self.hir.usize_ty();
-        let temp = self.temp(usize_ty);
+        let temp = self.temp(usize_ty, source_info.span);
         self.cfg.push_assign_constant(
             block, source_info, &temp,
             Constant {
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index db03a1c68f7..ef3fa23500b 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -249,7 +249,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             visibility_scopes: IndexVec::new(),
             visibility_scope: ARGUMENT_VISIBILITY_SCOPE,
             breakable_scopes: vec![],
-            local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty), 1),
+            local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty,
+                                                                             span), 1),
             var_indices: NodeMap(),
             unit_temp: None,
             cached_resume_block: None,
@@ -304,8 +305,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             self.local_decls.push(LocalDecl {
                 mutability: Mutability::Not,
                 ty: ty,
-                source_info: None,
+                source_info: SourceInfo {
+                    scope: ARGUMENT_VISIBILITY_SCOPE,
+                    span: pattern.map_or(self.fn_span, |pat| pat.span)
+                },
                 name: name,
+                is_user_variable: false,
             });
         }
 
@@ -341,7 +346,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             Some(ref tmp) => tmp.clone(),
             None => {
                 let ty = self.hir.unit_ty();
-                let tmp = self.temp(ty);
+                let fn_span = self.fn_span;
+                let tmp = self.temp(ty, fn_span);
                 self.unit_temp = Some(tmp.clone());
                 tmp
             }
diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs
index eb16812af9b..bb07081fe43 100644
--- a/src/librustc_mir/diagnostics.rs
+++ b/src/librustc_mir/diagnostics.rs
@@ -244,6 +244,39 @@ let baz: bool = { (&FOO as *const i32) == (&BAR as *const i32) };
 ```
 "##,
 
+E0161: r##"
+A value was moved. However, its size was not known at compile time, and only
+values of a known size can be moved.
+
+Erroneous code example:
+
+```compile_fail
+#![feature(box_syntax)]
+
+fn main() {
+    let array: &[isize] = &[1, 2, 3];
+    let _x: Box<[isize]> = box *array;
+    // error: cannot move a value of type [isize]: the size of [isize] cannot
+    //        be statically determined
+}
+```
+
+In Rust, you can only move a value when its size is known at compile time.
+
+To work around this restriction, consider "hiding" the value behind a reference:
+either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
+it around as usual. Example:
+
+```
+#![feature(box_syntax)]
+
+fn main() {
+    let array: &[isize] = &[1, 2, 3];
+    let _x: Box<&[isize]> = box array; // ok!
+}
+```
+"##,
+
 E0396: r##"
 The value behind a raw pointer can't be determined at compile-time
 (or even link-time), which means it can't be used in a constant
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 63d20be88fe..0cec84d16a8 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -137,16 +137,20 @@ enum CallKind {
     Direct(DefId),
 }
 
-fn temp_decl(mutability: Mutability, ty: Ty) -> LocalDecl {
-    LocalDecl { mutability, ty, name: None, source_info: None }
+fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl {
+    LocalDecl {
+        mutability, ty, name: None,
+        source_info: SourceInfo { scope: ARGUMENT_VISIBILITY_SCOPE, span },
+        is_user_variable: false
+    }
 }
 
-fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>)
+fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>, span: Span)
     -> IndexVec<Local, LocalDecl<'tcx>>
 {
-    iter::once(temp_decl(Mutability::Mut, sig.output()))
+    iter::once(temp_decl(Mutability::Mut, sig.output(), span))
         .chain(sig.inputs().iter().map(
-            |ity| temp_decl(Mutability::Not, ity)))
+            |ity| temp_decl(Mutability::Not, ity, span)))
         .collect()
 }
 
@@ -188,7 +192,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
         ),
         IndexVec::new(),
         sig.output(),
-        local_decls_for_sig(&sig),
+        local_decls_for_sig(&sig, span),
         sig.inputs().len(),
         vec![],
         span
@@ -297,7 +301,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
 
     debug!("build_call_shim: sig={:?}", sig);
 
-    let mut local_decls = local_decls_for_sig(&sig);
+    let mut local_decls = local_decls_for_sig(&sig, span);
     let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE };
 
     let rcvr_arg = Local::new(1+0);
@@ -317,7 +321,8 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
                 tcx.mk_ref(re_erased, ty::TypeAndMut {
                     ty: sig.inputs()[0],
                     mutbl: hir::Mutability::MutMutable
-                })
+                }),
+                span
             ));
             statements.push(Statement {
                 source_info: source_info,
@@ -442,7 +447,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
 
     debug!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id, sig, fields);
 
-    let local_decls = local_decls_for_sig(&sig);
+    let local_decls = local_decls_for_sig(&sig, span);
 
     let source_info = SourceInfo {
         span: span,
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 80a9c06f11b..ac2bdaad24f 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -461,11 +461,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
                 for loc in callee_mir.vars_and_temps_iter() {
                     let mut local = callee_mir.local_decls[loc].clone();
 
-                    if let Some(ref mut source_info) = local.source_info {
-                        source_info.scope = scope_map[source_info.scope];
-
-                        source_info.span = callsite.location.span;
-                    }
+                    local.source_info.scope = scope_map[local.source_info.scope];
+                    local.source_info.span = callsite.location.span;
 
                     let idx = caller_mir.local_decls.push(local);
                     local_map.push(idx);
@@ -506,7 +503,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
 
                     let ty = dest.ty(caller_mir, self.tcx);
 
-                    let temp = LocalDecl::new_temp(ty);
+                    let temp = LocalDecl::new_temp(ty, callsite.location.span);
 
                     let tmp = caller_mir.local_decls.push(temp);
                     let tmp = Lvalue::Local(tmp);
@@ -590,7 +587,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
             arg.deref());
 
         let ty = arg.ty(caller_mir, self.tcx);
-        let ref_tmp = LocalDecl::new_temp(ty);
+        let ref_tmp = LocalDecl::new_temp(ty, callsite.location.span);
         let ref_tmp = caller_mir.local_decls.push(ref_tmp);
         let ref_tmp = Lvalue::Local(ref_tmp);
 
@@ -611,7 +608,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
 
         let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Consume(ref_tmp), ptr_ty);
 
-        let cast_tmp = LocalDecl::new_temp(ptr_ty);
+        let cast_tmp = LocalDecl::new_temp(ptr_ty, callsite.location.span);
         let cast_tmp = caller_mir.local_decls.push(cast_tmp);
         let cast_tmp = Lvalue::Local(cast_tmp);
 
@@ -645,7 +642,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
 
             let ty = arg.ty(caller_mir, tcx);
 
-            let arg_tmp = LocalDecl::new_temp(ty);
+            let arg_tmp = LocalDecl::new_temp(ty, callsite.location.span);
             let arg_tmp = caller_mir.local_decls.push(arg_tmp);
             let arg_tmp = Lvalue::Local(arg_tmp);
 
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 57cf4b1e8b0..ed9a0d3809f 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -208,7 +208,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
 
         let no_stmts = self.source[loc.block].statements.len();
         let new_temp = self.promoted.local_decls.push(
-            LocalDecl::new_temp(self.source.local_decls[temp].ty));
+            LocalDecl::new_temp(self.source.local_decls[temp].ty,
+                                self.source.local_decls[temp].source_info.span));
 
         debug!("promote({:?} @ {:?}/{:?}, {:?})",
                temp, loc, no_stmts, self.keep_original);
@@ -379,7 +380,8 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
         };
 
         // Declare return pointer local
-        let initial_locals = iter::once(LocalDecl::new_return_pointer(ty)).collect();
+        let initial_locals = iter::once(LocalDecl::new_return_pointer(ty, span))
+            .collect();
 
         let mut promoter = Promoter {
             promoted: Mir::new(
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 8eabe92fb98..1313b24fa74 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -881,7 +881,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                 // Avoid a generic error for other uses of arguments.
                 if self.qualif.intersects(Qualif::FN_ARGUMENT) {
                     let decl = &self.mir.local_decls[index];
-                    span_err!(self.tcx.sess, decl.source_info.unwrap().span, E0022,
+                    span_err!(self.tcx.sess, decl.source_info.span, E0022,
                               "arguments of constant functions can only \
                                be immutable by-value bindings");
                     return;
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 3d604affbfe..bfb08de56d8 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -24,6 +24,7 @@ use std::fmt;
 use syntax::ast;
 use syntax_pos::{Span, DUMMY_SP};
 
+use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::indexed_vec::Idx;
 
 fn mirbug(tcx: TyCtxt, span: Span, msg: &str) {
@@ -87,6 +88,11 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
         self.sanitize_type(rvalue, rval_ty);
     }
 
+    fn visit_local_decl(&mut self, local_decl: &LocalDecl<'tcx>) {
+        self.super_local_decl(local_decl);
+        self.sanitize_type(local_decl, local_decl.ty);
+    }
+
     fn visit_mir(&mut self, mir: &Mir<'tcx>) {
         self.sanitize_type(&"return type", mir.return_ty);
         for local_decl in &mir.local_decls {
@@ -317,6 +323,7 @@ pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     fulfillment_cx: traits::FulfillmentContext<'tcx>,
     last_span: Span,
     body_id: ast::NodeId,
+    reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
 }
 
 impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
@@ -326,6 +333,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             fulfillment_cx: traits::FulfillmentContext::new(),
             last_span: DUMMY_SP,
             body_id: body_id,
+            reported_errors: FxHashSet(),
         }
     }
 
@@ -641,9 +649,43 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
+    fn check_local(&mut self, mir: &Mir<'gcx>, local: Local, local_decl: &LocalDecl<'gcx>) {
+        match mir.local_kind(local) {
+            LocalKind::ReturnPointer | LocalKind::Arg => {
+                // return values of normal functions are required to be
+                // sized by typeck, but return values of ADT constructors are
+                // not because we don't include a `Self: Sized` bounds on them.
+                //
+                // Unbound parts of arguments were never required to be Sized
+                // - maybe we should make that a warning.
+                return
+            }
+            LocalKind::Var | LocalKind::Temp => {}
+        }
+
+        let span = local_decl.source_info.span;
+        let ty = local_decl.ty;
+        if !ty.is_sized(self.tcx().global_tcx(), self.infcx.param_env(), span) {
+            // in current MIR construction, all non-control-flow rvalue
+            // expressions evaluate through `as_temp` or `into` a return
+            // slot or local, so to find all unsized rvalues it is enough
+            // to check all temps, return slots and locals.
+            if let None = self.reported_errors.replace((ty, span)) {
+                span_err!(self.tcx().sess, span, E0161,
+                          "cannot move a value of type {0}: the size of {0} \
+                           cannot be statically determined", ty);
+            }
+        }
+    }
+
+    fn typeck_mir(&mut self, mir: &Mir<'gcx>) {
         self.last_span = mir.span;
         debug!("run_on_mir: {:?}", mir.span);
+
+        for (local, local_decl) in mir.local_decls.iter_enumerated() {
+            self.check_local(mir, local, local_decl);
+        }
+
         for block in mir.basic_blocks() {
             for stmt in &block.statements {
                 if stmt.source_info.span != DUMMY_SP {
@@ -698,16 +740,18 @@ impl TypeckMir {
 impl<'tcx> MirPass<'tcx> for TypeckMir {
     fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     src: MirSource, mir: &mut Mir<'tcx>) {
-        debug!("run_pass: {}", tcx.node_path_str(src.item_id()));
+        let item_id = src.item_id();
+        let def_id = tcx.hir.local_def_id(item_id);
+        debug!("run_pass: {}", tcx.item_path_str(def_id));
 
         if tcx.sess.err_count() > 0 {
             // compiling a broken program can obviously result in a
             // broken MIR, so try not to report duplicate errors.
             return;
         }
-        let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
+        let param_env = ty::ParameterEnvironment::for_item(tcx, item_id);
         tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
-            let mut checker = TypeChecker::new(&infcx, src.item_id());
+            let mut checker = TypeChecker::new(&infcx, item_id);
             {
                 let mut verifier = TypeVerifier::new(&mut checker, mir);
                 verifier.visit_mir(mir);
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index ccbc6700d89..04a1fc891cf 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -686,7 +686,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
     }
 
     fn new_temp(&mut self, ty: Ty<'tcx>) -> Local {
-        self.elaborator.patch().new_temp(ty)
+        self.elaborator.patch().new_temp(ty, self.source_info.span)
     }
 
     fn terminator_loc(&mut self, bb: BasicBlock) -> Location {
diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs
index 19f240da730..7898d93c22e 100644
--- a/src/librustc_mir/util/patch.rs
+++ b/src/librustc_mir/util/patch.rs
@@ -11,6 +11,7 @@
 use rustc::ty::Ty;
 use rustc::mir::*;
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use syntax_pos::Span;
 
 /// This struct represents a patch to MIR, which can add
 /// new statements and basic blocks and patch over block
@@ -92,10 +93,10 @@ impl<'tcx> MirPatch<'tcx> {
         }
     }
 
-    pub fn new_temp(&mut self, ty: Ty<'tcx>) -> Local {
+    pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local {
         let index = self.next_local;
         self.next_local += 1;
-        self.new_locals.push(LocalDecl::new_temp(ty));
+        self.new_locals.push(LocalDecl::new_temp(ty, span));
         Local::new(index as usize)
     }
 
diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs
index ef2bf6e5434..b202e149510 100644
--- a/src/librustc_mir/util/pretty.rs
+++ b/src/librustc_mir/util/pretty.rs
@@ -196,8 +196,8 @@ fn write_scope_tree(tcx: TyCtxt,
         // User variable types (including the user's name in a comment).
         for local in mir.vars_iter() {
             let var = &mir.local_decls[local];
-            let (name, source_info) = if var.source_info.unwrap().scope == child {
-                (var.name.unwrap(), var.source_info.unwrap())
+            let (name, source_info) = if var.source_info.scope == child {
+                (var.name.unwrap(), var.source_info)
             } else {
                 // Not a variable or not declared in this scope.
                 continue;
diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs
index 5f06eadb84a..036a52d5a3d 100644
--- a/src/librustc_passes/diagnostics.rs
+++ b/src/librustc_passes/diagnostics.rs
@@ -82,39 +82,6 @@ extern {
 ```
 "##,
 
-E0161: r##"
-A value was moved. However, its size was not known at compile time, and only
-values of a known size can be moved.
-
-Erroneous code example:
-
-```compile_fail
-#![feature(box_syntax)]
-
-fn main() {
-    let array: &[isize] = &[1, 2, 3];
-    let _x: Box<[isize]> = box *array;
-    // error: cannot move a value of type [isize]: the size of [isize] cannot
-    //        be statically determined
-}
-```
-
-In Rust, you can only move a value when its size is known at compile time.
-
-To work around this restriction, consider "hiding" the value behind a reference:
-either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
-it around as usual. Example:
-
-```
-#![feature(box_syntax)]
-
-fn main() {
-    let array: &[isize] = &[1, 2, 3];
-    let _x: Box<&[isize]> = box array; // ok!
-}
-```
-"##,
-
 E0265: r##"
 This error indicates that a static or constant references itself.
 All statics and constants need to resolve to a value in an acyclic manner.
diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs
index 7a465f0ec42..22566c813d8 100644
--- a/src/librustc_passes/lib.rs
+++ b/src/librustc_passes/lib.rs
@@ -47,5 +47,4 @@ pub mod hir_stats;
 pub mod loops;
 pub mod mir_stats;
 pub mod no_asm;
-pub mod rvalues;
 pub mod static_recursion;
diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs
deleted file mode 100644
index c367e71fcd2..00000000000
--- a/src/librustc_passes/rvalues.rs
+++ /dev/null
@@ -1,103 +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.
-
-// Checks that all rvalues in a crate have statically known size. check_crate
-// is the public starting point.
-
-use rustc::dep_graph::DepNode;
-use rustc::middle::expr_use_visitor as euv;
-use rustc::middle::mem_categorization as mc;
-use rustc::ty::{self, TyCtxt};
-use rustc::traits::Reveal;
-
-use rustc::hir;
-use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
-use syntax::ast;
-use syntax_pos::Span;
-
-pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    let mut rvcx = RvalueContext { tcx: tcx };
-    tcx.visit_all_item_likes_in_krate(DepNode::RvalueCheck, &mut rvcx.as_deep_visitor());
-}
-
-struct RvalueContext<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_nested_body(&mut self, body_id: hir::BodyId) {
-        let body = self.tcx.hir.body(body_id);
-        self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
-            let mut delegate = RvalueContextDelegate {
-                tcx: infcx.tcx,
-                param_env: &infcx.parameter_environment
-            };
-            euv::ExprUseVisitor::new(&mut delegate, &infcx).consume_body(body);
-        });
-        self.visit_body(body);
-    }
-}
-
-struct RvalueContextDelegate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    param_env: &'a ty::ParameterEnvironment<'gcx>,
-}
-
-impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'gcx, 'tcx> {
-    fn consume(&mut self,
-               _: ast::NodeId,
-               span: Span,
-               cmt: mc::cmt<'tcx>,
-               _: euv::ConsumeMode) {
-        debug!("consume; cmt: {:?}; type: {:?}", *cmt, cmt.ty);
-        let ty = self.tcx.lift_to_global(&cmt.ty).unwrap();
-        if !ty.is_sized(self.tcx.global_tcx(), self.param_env, span) {
-            span_err!(self.tcx.sess, span, E0161,
-                "cannot move a value of type {0}: the size of {0} cannot be statically determined",
-                ty);
-        }
-    }
-
-    fn matched_pat(&mut self,
-                   _matched_pat: &hir::Pat,
-                   _cmt: mc::cmt,
-                   _mode: euv::MatchMode) {}
-
-    fn consume_pat(&mut self,
-                   _consume_pat: &hir::Pat,
-                   _cmt: mc::cmt,
-                   _mode: euv::ConsumeMode) {
-    }
-
-    fn borrow(&mut self,
-              _borrow_id: ast::NodeId,
-              _borrow_span: Span,
-              _cmt: mc::cmt,
-              _loan_region: &'tcx ty::Region,
-              _bk: ty::BorrowKind,
-              _loan_cause: euv::LoanCause) {
-    }
-
-    fn decl_without_init(&mut self,
-                         _id: ast::NodeId,
-                         _span: Span) {
-    }
-
-    fn mutate(&mut self,
-              _assignment_id: ast::NodeId,
-              _assignment_span: Span,
-              _assignee_cmt: mc::cmt,
-              _mode: euv::MutateMode) {
-    }
-}
diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs
index c6f8ba7b6dc..3d074c31c8a 100644
--- a/src/librustc_trans/debuginfo/create_scope_map.rs
+++ b/src/librustc_trans/debuginfo/create_scope_map.rs
@@ -65,7 +65,7 @@ pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &Function
     let mut has_variables = BitVector::new(mir.visibility_scopes.len());
     for var in mir.vars_iter() {
         let decl = &mir.local_decls[var];
-        has_variables.insert(decl.source_info.unwrap().scope.index());
+        has_variables.insert(decl.source_info.scope.index());
     }
 
     // Instantiate all scopes.
diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs
index f4c9a136ace..c51e1fb0028 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -255,8 +255,7 @@ pub fn trans_mir<'a, 'tcx: 'a>(
 
             if let Some(name) = decl.name {
                 // User variable
-                let source_info = decl.source_info.unwrap();
-                let debug_scope = mircx.scopes[source_info.scope];
+                let debug_scope = mircx.scopes[decl.source_info.scope];
                 let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo;
 
                 if !lvalue_locals.contains(local.index()) && !dbg {
@@ -268,7 +267,7 @@ pub fn trans_mir<'a, 'tcx: 'a>(
                 assert!(!ty.has_erasable_regions());
                 let lvalue = LvalueRef::alloca(&bcx, ty, &name.as_str());
                 if dbg {
-                    let (scope, span) = mircx.debug_loc(source_info);
+                    let (scope, span) = mircx.debug_loc(decl.source_info);
                     declare_local(&bcx, &mircx.debug_context, name, ty, scope,
                         VariableAccess::DirectVariable { alloca: lvalue.llval },
                         VariableKind::LocalVariable, span);
diff --git a/src/test/compile-fail/issue-41139.rs b/src/test/compile-fail/issue-41139.rs
new file mode 100644
index 00000000000..15ca151c49a
--- /dev/null
+++ b/src/test/compile-fail/issue-41139.rs
@@ -0,0 +1,18 @@
+// 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.
+
+trait Trait {}
+
+fn get_function<'a>() -> &'a Fn() -> Trait { panic!("") }
+
+fn main() {
+    let t : &Trait = &get_function()();
+    //~^ ERROR cannot move a value of type Trait + 'static
+}