about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc_middle/mir/mod.rs116
-rw-r--r--src/librustc_middle/mir/visit.rs22
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs8
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/mod.rs2
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/move_errors.rs11
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs18
-rw-r--r--src/librustc_mir/borrow_check/type_check/mod.rs57
-rw-r--r--src/librustc_mir/dataflow/framework/tests.rs2
-rw-r--r--src/librustc_mir/shim.rs53
-rw-r--r--src/librustc_mir/transform/add_retag.rs8
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs2
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs4
-rw-r--r--src/librustc_mir/transform/generator.rs56
-rw-r--r--src/librustc_mir/transform/inline.rs4
-rw-r--r--src/librustc_mir/transform/promote_consts.rs13
-rw-r--r--src/librustc_mir/util/patch.rs6
-rw-r--r--src/librustc_mir/util/pretty.rs6
-rw-r--r--src/librustc_mir_build/build/expr/as_place.rs2
-rw-r--r--src/librustc_mir_build/build/expr/as_rvalue.rs4
-rw-r--r--src/librustc_mir_build/build/expr/as_temp.rs4
-rw-r--r--src/librustc_mir_build/build/expr/into.rs13
-rw-r--r--src/librustc_mir_build/build/matches/mod.rs16
-rw-r--r--src/librustc_mir_build/build/misc.rs2
-rw-r--r--src/librustc_mir_build/build/mod.rs42
-rw-r--r--src/librustc_mir_build/build/scope.rs2
25 files changed, 206 insertions, 267 deletions
diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs
index 8d416536155..15862660512 100644
--- a/src/librustc_middle/mir/mod.rs
+++ b/src/librustc_middle/mir/mod.rs
@@ -474,6 +474,13 @@ pub struct SourceInfo {
     pub scope: SourceScope,
 }
 
+impl SourceInfo {
+    #[inline]
+    pub fn outermost(span: Span) -> Self {
+        SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // Borrow kinds
 
@@ -689,7 +696,7 @@ pub struct LocalDecl<'tcx> {
     pub mutability: Mutability,
 
     // FIXME(matthewjasper) Don't store in this in `Body`
-    pub local_info: LocalInfo<'tcx>,
+    pub local_info: Option<Box<LocalInfo<'tcx>>>,
 
     /// `true` if this is an internal local.
     ///
@@ -725,7 +732,7 @@ pub struct LocalDecl<'tcx> {
     /// borrow checker needs this information since it can affect
     /// region inference.
     // FIXME(matthewjasper) Don't store in this in `Body`
-    pub user_ty: UserTypeProjections,
+    pub user_ty: Option<Box<UserTypeProjections>>,
 
     /// The *syntactic* (i.e., not visibility) source scope the local is defined
     /// in. If the local was defined in a let-statement, this
@@ -809,7 +816,13 @@ pub struct LocalDecl<'tcx> {
     pub source_info: SourceInfo,
 }
 
-/// Extra information about a local that's used for diagnostics.
+// `LocalDecl` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(LocalDecl<'_>, 56);
+
+/// Extra information about a some locals that's used for diagnostics. (Not
+/// used for non-StaticRef temporaries, the return place, or anonymous function
+/// parameters.)
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
 pub enum LocalInfo<'tcx> {
     /// A user-defined local variable or function parameter
@@ -820,8 +833,6 @@ pub enum LocalInfo<'tcx> {
     User(ClearCrossCrate<BindingForm<'tcx>>),
     /// A temporary created that references the static with the given `DefId`.
     StaticRef { def_id: DefId, is_thread_local: bool },
-    /// Any other temporary, the return place, or an anonymous function parameter.
-    Other,
 }
 
 impl<'tcx> LocalDecl<'tcx> {
@@ -833,16 +844,16 @@ impl<'tcx> LocalDecl<'tcx> {
     /// - or `match ... { C(x) => ... }`
     pub fn can_be_made_mutable(&self) -> bool {
         match self.local_info {
-            LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
                 binding_mode: ty::BindingMode::BindByValue(_),
                 opt_ty_info: _,
                 opt_match_place: _,
                 pat_span: _,
-            }))) => true,
+            })))) => true,
 
-            LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
+            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
                 ImplicitSelfKind::Imm,
-            ))) => true,
+            )))) => true,
 
             _ => false,
         }
@@ -853,14 +864,14 @@ impl<'tcx> LocalDecl<'tcx> {
     /// mutable bindings, but the inverse does not necessarily hold).
     pub fn is_nonref_binding(&self) -> bool {
         match self.local_info {
-            LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
                 binding_mode: ty::BindingMode::BindByValue(_),
                 opt_ty_info: _,
                 opt_match_place: _,
                 pat_span: _,
-            }))) => true,
+            })))) => true,
 
-            LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_))) => true,
+            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_)))) => true,
 
             _ => false,
         }
@@ -871,7 +882,7 @@ impl<'tcx> LocalDecl<'tcx> {
     #[inline]
     pub fn is_user_variable(&self) -> bool {
         match self.local_info {
-            LocalInfo::User(_) => true,
+            Some(box LocalInfo::User(_)) => true,
             _ => false,
         }
     }
@@ -881,7 +892,7 @@ impl<'tcx> LocalDecl<'tcx> {
     /// match arm.
     pub fn is_ref_for_guard(&self) -> bool {
         match self.local_info {
-            LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)) => true,
+            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard))) => true,
             _ => false,
         }
     }
@@ -890,7 +901,7 @@ impl<'tcx> LocalDecl<'tcx> {
     /// access that static
     pub fn is_ref_to_static(&self) -> bool {
         match self.local_info {
-            LocalInfo::StaticRef { .. } => true,
+            Some(box LocalInfo::StaticRef { .. }) => true,
             _ => false,
         }
     }
@@ -899,7 +910,7 @@ impl<'tcx> LocalDecl<'tcx> {
     /// access that static
     pub fn is_ref_to_thread_local(&self) -> bool {
         match self.local_info {
-            LocalInfo::StaticRef { is_thread_local, .. } => is_thread_local,
+            Some(box LocalInfo::StaticRef { is_thread_local, .. }) => is_thread_local,
             _ => false,
         }
     }
@@ -911,10 +922,31 @@ impl<'tcx> LocalDecl<'tcx> {
         self.source_info.span.desugaring_kind().is_some()
     }
 
-    /// Creates a new `LocalDecl` for a temporary.
+    /// Creates a new `LocalDecl` for a temporary: mutable, non-internal.
     #[inline]
-    pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self {
-        Self::new_local(ty, Mutability::Mut, false, span)
+    pub fn new(ty: Ty<'tcx>, span: Span) -> Self {
+        Self::with_source_info(ty, SourceInfo::outermost(span))
+    }
+
+    /// Like `LocalDecl::new`, but takes a `SourceInfo` instead of a `Span`.
+    #[inline]
+    pub fn with_source_info(ty: Ty<'tcx>, source_info: SourceInfo) -> Self {
+        LocalDecl {
+            mutability: Mutability::Mut,
+            local_info: None,
+            internal: false,
+            is_block_tail: None,
+            ty,
+            user_ty: None,
+            source_info,
+        }
+    }
+
+    /// Converts `self` into same `LocalDecl` except tagged as internal.
+    #[inline]
+    pub fn internal(mut self) -> Self {
+        self.internal = true;
+        self
     }
 
     /// Converts `self` into same `LocalDecl` except tagged as immutable.
@@ -931,41 +963,6 @@ impl<'tcx> LocalDecl<'tcx> {
         self.is_block_tail = Some(info);
         self
     }
-
-    /// Creates a new `LocalDecl` for a internal temporary.
-    #[inline]
-    pub fn new_internal(ty: Ty<'tcx>, span: Span) -> Self {
-        Self::new_local(ty, Mutability::Mut, true, span)
-    }
-
-    #[inline]
-    fn new_local(ty: Ty<'tcx>, mutability: Mutability, internal: bool, span: Span) -> Self {
-        LocalDecl {
-            mutability,
-            ty,
-            user_ty: UserTypeProjections::none(),
-            source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
-            internal,
-            local_info: LocalInfo::Other,
-            is_block_tail: None,
-        }
-    }
-
-    /// Builds a `LocalDecl` for the return place.
-    ///
-    /// This must be inserted into the `local_decls` list as the first local.
-    #[inline]
-    pub fn new_return_place(return_ty: Ty<'_>, span: Span) -> LocalDecl<'_> {
-        LocalDecl {
-            mutability: Mutability::Mut,
-            ty: return_ty,
-            user_ty: UserTypeProjections::none(),
-            source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
-            internal: false,
-            is_block_tail: None,
-            local_info: LocalInfo::Other,
-        }
-    }
 }
 
 /// Debug information pertaining to a user variable.
@@ -1406,10 +1403,7 @@ impl<'tcx> BasicBlockData<'tcx> {
         let mut gap = self.statements.len()..self.statements.len() + extra_stmts;
         self.statements.resize(
             gap.end,
-            Statement {
-                source_info: SourceInfo { span: DUMMY_SP, scope: OUTERMOST_SOURCE_SCOPE },
-                kind: StatementKind::Nop,
-            },
+            Statement { source_info: SourceInfo::outermost(DUMMY_SP), kind: StatementKind::Nop },
         );
         for (splice_start, new_stmts) in splices.into_iter().rev() {
             let splice_end = splice_start + new_stmts.size_hint().0;
@@ -2457,7 +2451,7 @@ impl Constant<'tcx> {
 /// &'static str`.
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
 pub struct UserTypeProjections {
-    pub(crate) contents: Vec<(UserTypeProjection, Span)>,
+    pub contents: Vec<(UserTypeProjection, Span)>,
 }
 
 impl<'tcx> UserTypeProjections {
@@ -2465,6 +2459,10 @@ impl<'tcx> UserTypeProjections {
         UserTypeProjections { contents: vec![] }
     }
 
+    pub fn is_empty(&self) -> bool {
+        self.contents.is_empty()
+    }
+
     pub fn from_projections(projs: impl Iterator<Item = (UserTypeProjection, Span)>) -> Self {
         UserTypeProjections { contents: projs.collect() }
     }
diff --git a/src/librustc_middle/mir/visit.rs b/src/librustc_middle/mir/visit.rs
index 97f7cccdb60..2f3d89dc029 100644
--- a/src/librustc_middle/mir/visit.rs
+++ b/src/librustc_middle/mir/visit.rs
@@ -242,10 +242,10 @@ macro_rules! make_mir_visitor {
             ) {
                 let span = body.span;
                 if let Some(yield_ty) = &$($mutability)? body.yield_ty {
-                    self.visit_ty(yield_ty, TyContext::YieldTy(SourceInfo {
-                        span,
-                        scope: OUTERMOST_SOURCE_SCOPE,
-                    }));
+                    self.visit_ty(
+                        yield_ty,
+                        TyContext::YieldTy(SourceInfo::outermost(span))
+                    );
                 }
 
                 // for best performance, we want to use an iterator rather
@@ -263,10 +263,10 @@ macro_rules! make_mir_visitor {
                     self.visit_source_scope_data(scope);
                 }
 
-                self.visit_ty(&$($mutability)? body.return_ty(), TyContext::ReturnTy(SourceInfo {
-                    span: body.span,
-                    scope: OUTERMOST_SOURCE_SCOPE,
-                }));
+                self.visit_ty(
+                    &$($mutability)? body.return_ty(),
+                    TyContext::ReturnTy(SourceInfo::outermost(body.span))
+                );
 
                 for local in body.local_decls.indices() {
                     self.visit_local_decl(local, & $($mutability)? body.local_decls[local]);
@@ -715,8 +715,10 @@ macro_rules! make_mir_visitor {
                     local,
                     source_info: *source_info,
                 });
-                for (user_ty, _) in & $($mutability)? user_ty.contents {
-                    self.visit_user_type_projection(user_ty);
+                if let Some(user_ty) = user_ty {
+                    for (user_ty, _) in & $($mutability)? user_ty.contents {
+                        self.visit_user_type_projection(user_ty);
+                    }
                 }
                 self.visit_source_info(source_info);
             }
diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
index 14a094b9d52..5f1c0911da2 100644
--- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
@@ -1447,15 +1447,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let (place_description, assigned_span) = match local_decl {
             Some(LocalDecl {
                 local_info:
-                    LocalInfo::User(
+                    Some(box LocalInfo::User(
                         ClearCrossCrate::Clear
                         | ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
                             opt_match_place: None,
                             ..
                         })),
-                    )
-                    | LocalInfo::StaticRef { .. }
-                    | LocalInfo::Other,
+                    ))
+                    | Some(box LocalInfo::StaticRef { .. })
+                    | None,
                 ..
             })
             | None => (self.describe_any_place(place.as_ref()), assigned_span),
diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs
index 9e4458e7104..c218e3906ff 100644
--- a/src/librustc_mir/borrow_check/diagnostics/mod.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs
@@ -202,7 +202,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 if self.body.local_decls[local].is_ref_to_static() =>
             {
                 let local_info = &self.body.local_decls[local].local_info;
-                if let LocalInfo::StaticRef { def_id, .. } = *local_info {
+                if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info {
                     buf.push_str(&self.infcx.tcx.item_name(def_id).as_str());
                 } else {
                     unreachable!();
diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
index 457e263a466..67254811ec5 100644
--- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
@@ -103,14 +103,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         //
                         // opt_match_place is None for let [mut] x = ... statements,
                         // whether or not the right-hand side is a place expression
-                        if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+                        if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
                             VarBindingForm {
                                 opt_match_place: Some((opt_match_place, match_span)),
                                 binding_mode: _,
                                 opt_ty_info: _,
                                 pat_span: _,
                             },
-                        ))) = local_decl.local_info
+                        )))) = local_decl.local_info
                         {
                             let stmt_source_info = self.body.source_info(location);
                             self.append_binding_error(
@@ -482,10 +482,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         let mut suggestions: Vec<(Span, &str, String)> = Vec::new();
         for local in binds_to {
             let bind_to = &self.body.local_decls[*local];
-            if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
-                pat_span,
-                ..
-            }))) = bind_to.local_info
+            if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+                VarBindingForm { pat_span, .. },
+            )))) = bind_to.local_info
             {
                 if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span)
                 {
diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
index 1a4876db0de..402eac47c46 100644
--- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
@@ -85,7 +85,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 } else {
                     item_msg = format!("`{}`", access_place_desc.unwrap());
                     let local_info = &self.body.local_decls[local].local_info;
-                    if let LocalInfo::StaticRef { def_id, .. } = *local_info {
+                    if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info {
                         let static_name = &self.infcx.tcx.item_name(def_id);
                         reason = format!(", as `{}` is an immutable static item", static_name);
                     } else {
@@ -216,9 +216,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         .local_decls
                         .get(local)
                         .map(|local_decl| {
-                            if let LocalInfo::User(ClearCrossCrate::Set(
+                            if let Some(box LocalInfo::User(ClearCrossCrate::Set(
                                 mir::BindingForm::ImplicitSelf(kind),
-                            )) = local_decl.local_info
+                            ))) = local_decl.local_info
                             {
                                 // Check if the user variable is a `&mut self` and we can therefore
                                 // suggest removing the `&mut`.
@@ -340,8 +340,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
                 match self.local_names[local] {
                     Some(name) if !local_decl.from_compiler_desugaring() => {
-                        let label = match local_decl.local_info {
-                            LocalInfo::User(ClearCrossCrate::Set(
+                        let label = match local_decl.local_info.as_ref().unwrap() {
+                            box LocalInfo::User(ClearCrossCrate::Set(
                                 mir::BindingForm::ImplicitSelf(_),
                             )) => {
                                 let (span, suggestion) =
@@ -349,7 +349,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                 Some((true, span, suggestion))
                             }
 
-                            LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
+                            box LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
                                 mir::VarBindingForm {
                                     binding_mode: ty::BindingMode::BindByValue(_),
                                     opt_ty_info,
@@ -381,14 +381,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                             self.infcx.tcx,
                                             local_decl,
                                             opt_assignment_rhs_span,
-                                            opt_ty_info,
+                                            *opt_ty_info,
                                         );
                                         Some((true, span, suggestion))
                                     }
                                 }
                             }
 
-                            LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
+                            box LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
                                 mir::VarBindingForm {
                                     binding_mode: ty::BindingMode::BindByReference(_),
                                     ..
@@ -399,7 +399,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                     .map(|replacement| (true, pattern_span, replacement))
                             }
 
-                            LocalInfo::User(ClearCrossCrate::Clear) => {
+                            box LocalInfo::User(ClearCrossCrate::Clear) => {
                                 bug!("saw cleared local state")
                             }
 
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index 7533bdfbd8d..ee8a4358147 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -405,35 +405,38 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
         self.super_local_decl(local, local_decl);
         self.sanitize_type(local_decl, local_decl.ty);
 
-        for (user_ty, span) in local_decl.user_ty.projections_and_spans() {
-            let ty = if !local_decl.is_nonref_binding() {
-                // If we have a binding of the form `let ref x: T = ..` then remove the outermost
-                // reference so we can check the type annotation for the remaining type.
-                if let ty::Ref(_, rty, _) = local_decl.ty.kind {
-                    rty
+        if let Some(user_ty) = &local_decl.user_ty {
+            for (user_ty, span) in user_ty.projections_and_spans() {
+                let ty = if !local_decl.is_nonref_binding() {
+                    // If we have a binding of the form `let ref x: T = ..`
+                    // then remove the outermost reference so we can check the
+                    // type annotation for the remaining type.
+                    if let ty::Ref(_, rty, _) = local_decl.ty.kind {
+                        rty
+                    } else {
+                        bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty);
+                    }
                 } else {
-                    bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty);
-                }
-            } else {
-                local_decl.ty
-            };
+                    local_decl.ty
+                };
 
-            if let Err(terr) = self.cx.relate_type_and_user_type(
-                ty,
-                ty::Variance::Invariant,
-                user_ty,
-                Locations::All(*span),
-                ConstraintCategory::TypeAnnotation,
-            ) {
-                span_mirbug!(
-                    self,
-                    local,
-                    "bad user type on variable {:?}: {:?} != {:?} ({:?})",
-                    local,
-                    local_decl.ty,
-                    local_decl.user_ty,
-                    terr,
-                );
+                if let Err(terr) = self.cx.relate_type_and_user_type(
+                    ty,
+                    ty::Variance::Invariant,
+                    user_ty,
+                    Locations::All(*span),
+                    ConstraintCategory::TypeAnnotation,
+                ) {
+                    span_mirbug!(
+                        self,
+                        local,
+                        "bad user type on variable {:?}: {:?} != {:?} ({:?})",
+                        local,
+                        local_decl.ty,
+                        local_decl.user_ty,
+                        terr,
+                    );
+                }
             }
         }
     }
diff --git a/src/librustc_mir/dataflow/framework/tests.rs b/src/librustc_mir/dataflow/framework/tests.rs
index a8dce7079b7..3ed0a9594e7 100644
--- a/src/librustc_mir/dataflow/framework/tests.rs
+++ b/src/librustc_mir/dataflow/framework/tests.rs
@@ -16,7 +16,7 @@ use crate::dataflow::BottomValue;
 /// This is the `Body` that will be used by the `MockAnalysis` below. The shape of its CFG is not
 /// important.
 fn mock_body() -> mir::Body<'static> {
-    let source_info = mir::SourceInfo { scope: mir::OUTERMOST_SOURCE_SCOPE, span: DUMMY_SP };
+    let source_info = mir::SourceInfo::outermost(DUMMY_SP);
 
     let mut blocks = IndexVec::new();
     let mut block = |n, kind| {
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index dfa1bb764e4..847f59b95e9 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -145,25 +145,12 @@ enum CallKind {
     Direct(DefId),
 }
 
-fn temp_decl(mutability: Mutability, ty: Ty<'_>, span: Span) -> LocalDecl<'_> {
-    let source_info = SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span };
-    LocalDecl {
-        mutability,
-        ty,
-        user_ty: UserTypeProjections::none(),
-        source_info,
-        internal: false,
-        local_info: LocalInfo::Other,
-        is_block_tail: None,
-    }
-}
-
 fn local_decls_for_sig<'tcx>(
     sig: &ty::FnSig<'tcx>,
     span: Span,
 ) -> IndexVec<Local, LocalDecl<'tcx>> {
-    iter::once(temp_decl(Mutability::Mut, sig.output(), span))
-        .chain(sig.inputs().iter().map(|ity| temp_decl(Mutability::Not, ity, span)))
+    iter::once(LocalDecl::new(sig.output(), span))
+        .chain(sig.inputs().iter().map(|ity| LocalDecl::new(ity, span).immutable()))
         .collect()
 }
 
@@ -185,7 +172,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
     let sig = tcx.erase_late_bound_regions(&sig);
     let span = tcx.def_span(def_id);
 
-    let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };
+    let source_info = SourceInfo::outermost(span);
 
     let return_block = BasicBlock::new(1);
     let mut blocks = IndexVec::with_capacity(2);
@@ -374,7 +361,7 @@ impl CloneShimBuilder<'tcx> {
     }
 
     fn source_info(&self) -> SourceInfo {
-        SourceInfo { span: self.span, scope: OUTERMOST_SOURCE_SCOPE }
+        SourceInfo::outermost(self.span)
     }
 
     fn block(
@@ -414,7 +401,11 @@ impl CloneShimBuilder<'tcx> {
 
     fn make_place(&mut self, mutability: Mutability, ty: Ty<'tcx>) -> Place<'tcx> {
         let span = self.span;
-        Place::from(self.local_decls.push(temp_decl(mutability, ty, span)))
+        let mut local = LocalDecl::new(ty, span);
+        if mutability == Mutability::Not {
+            local = local.immutable();
+        }
+        Place::from(self.local_decls.push(local))
     }
 
     fn make_clone_call(
@@ -498,7 +489,7 @@ impl CloneShimBuilder<'tcx> {
         let tcx = self.tcx;
         let span = self.span;
 
-        let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
+        let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span));
         let end = self.make_place(Mutability::Not, tcx.types.usize);
 
         // BB #0
@@ -553,7 +544,7 @@ impl CloneShimBuilder<'tcx> {
         // `let mut beg = 0;`
         // goto #6;
         let end = beg;
-        let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
+        let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span));
         let init = self.make_statement(StatementKind::Assign(box (
             Place::from(beg),
             Rvalue::Use(Operand::Constant(self.make_usize(0))),
@@ -687,7 +678,7 @@ fn build_call_shim<'tcx>(
     debug!("build_call_shim: sig={:?}", sig);
 
     let mut local_decls = local_decls_for_sig(&sig, span);
-    let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };
+    let source_info = SourceInfo::outermost(span);
 
     let rcvr_place = || {
         assert!(rcvr_adjustment.is_some());
@@ -701,14 +692,16 @@ fn build_call_shim<'tcx>(
         Adjustment::DerefMove => Operand::Move(tcx.mk_place_deref(rcvr_place())),
         Adjustment::RefMut => {
             // let rcvr = &mut rcvr;
-            let ref_rcvr = local_decls.push(temp_decl(
-                Mutability::Not,
-                tcx.mk_ref(
-                    tcx.lifetimes.re_erased,
-                    ty::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::Mut },
-                ),
-                span,
-            ));
+            let ref_rcvr = local_decls.push(
+                LocalDecl::new(
+                    tcx.mk_ref(
+                        tcx.lifetimes.re_erased,
+                        ty::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::Mut },
+                    ),
+                    span,
+                )
+                .immutable(),
+            );
             let borrow_kind = BorrowKind::Mut { allow_two_phase_borrow: false };
             statements.push(Statement {
                 source_info,
@@ -849,7 +842,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
 
     let local_decls = local_decls_for_sig(&sig, span);
 
-    let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };
+    let source_info = SourceInfo::outermost(span);
 
     let variant_index = if adt_def.is_enum() {
         adt_def.variant_index_with_ctor_id(ctor_id)
diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs
index 6d5853def1e..baa3e5e1581 100644
--- a/src/librustc_mir/transform/add_retag.rs
+++ b/src/librustc_mir/transform/add_retag.rs
@@ -77,11 +77,9 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
         // PART 1
         // Retag arguments at the beginning of the start block.
         {
-            let source_info = SourceInfo {
-                scope: OUTERMOST_SOURCE_SCOPE,
-                span, // FIXME: Consider using just the span covering the function
-                      // argument declaration.
-            };
+            // FIXME: Consider using just the span covering the function
+            // argument declaration.
+            let source_info = SourceInfo::outermost(span);
             // Gather all arguments, skip return value.
             let places = local_decls
                 .iter_enumerated()
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index 896ce981f92..8c005fdcdbf 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -455,7 +455,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                     if proj_base.is_empty() {
                         if let (local, []) = (place_local, proj_base) {
                             let decl = &self.body.local_decls[local];
-                            if let LocalInfo::StaticRef { def_id, .. } = decl.local_info {
+                            if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
                                 let span = decl.source_info.span;
                                 self.check_static(def_id, span);
                                 return;
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index a8487be77de..0bd9b3e1b20 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -50,7 +50,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
             const_context,
             min_const_fn,
             violations: vec![],
-            source_info: SourceInfo { span: body.span, scope: OUTERMOST_SOURCE_SCOPE },
+            source_info: SourceInfo::outermost(body.span),
             tcx,
             param_env,
             used_unsafe: Default::default(),
@@ -218,7 +218,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
             if let [] = proj_base {
                 let decl = &self.body.local_decls[place.local];
                 if decl.internal {
-                    if let LocalInfo::StaticRef { def_id, .. } = decl.local_info {
+                    if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
                         if self.tcx.is_mutable_static(def_id) {
                             self.require_unsafe(
                                 "use of mutable static",
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index b5e691ef029..d334006d7b5 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -255,13 +255,13 @@ impl TransformVisitor<'tcx> {
 
     // Create a statement which reads the discriminant into a temporary
     fn get_discr(&self, body: &mut Body<'tcx>) -> (Statement<'tcx>, Place<'tcx>) {
-        let temp_decl = LocalDecl::new_internal(self.tcx.types.isize, body.span);
+        let temp_decl = LocalDecl::new(self.tcx.types.isize, body.span).internal();
         let local_decls_len = body.local_decls.push(temp_decl);
         let temp = Place::from(local_decls_len);
 
         let self_place = Place::from(SELF_ARG);
         let assign = Statement {
-            source_info: source_info(body),
+            source_info: SourceInfo::outermost(body.span),
             kind: StatementKind::Assign(box (temp, Rvalue::Discriminant(self_place))),
         };
         (assign, temp)
@@ -395,16 +395,7 @@ fn replace_local<'tcx>(
     body: &mut Body<'tcx>,
     tcx: TyCtxt<'tcx>,
 ) -> Local {
-    let source_info = source_info(body);
-    let new_decl = LocalDecl {
-        mutability: Mutability::Mut,
-        ty,
-        user_ty: UserTypeProjections::none(),
-        source_info,
-        internal: false,
-        is_block_tail: None,
-        local_info: LocalInfo::Other,
-    };
+    let new_decl = LocalDecl::new(ty, body.span);
     let new_local = body.local_decls.push(new_decl);
     body.local_decls.swap(local, new_local);
 
@@ -784,7 +775,7 @@ fn insert_switch<'tcx>(
         targets: cases.iter().map(|&(_, d)| d).chain(iter::once(default_block)).collect(),
     };
 
-    let source_info = source_info(body);
+    let source_info = SourceInfo::outermost(body.span);
     body.basic_blocks_mut().raw.insert(
         0,
         BasicBlockData {
@@ -858,7 +849,7 @@ fn create_generator_drop_shim<'tcx>(
     let mut body = body.clone();
     body.arg_count = 1; // make sure the resume argument is not included here
 
-    let source_info = source_info(&body);
+    let source_info = SourceInfo::outermost(body.span);
 
     let mut cases = create_cases(&mut body, transform, Operation::Drop);
 
@@ -877,28 +868,15 @@ fn create_generator_drop_shim<'tcx>(
     }
 
     // Replace the return variable
-    body.local_decls[RETURN_PLACE] = LocalDecl {
-        mutability: Mutability::Mut,
-        ty: tcx.mk_unit(),
-        user_ty: UserTypeProjections::none(),
-        source_info,
-        internal: false,
-        is_block_tail: None,
-        local_info: LocalInfo::Other,
-    };
+    body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(tcx.mk_unit(), source_info);
 
     make_generator_state_argument_indirect(tcx, &mut body);
 
     // Change the generator argument from &mut to *mut
-    body.local_decls[SELF_ARG] = LocalDecl {
-        mutability: Mutability::Mut,
-        ty: tcx.mk_ptr(ty::TypeAndMut { ty: gen_ty, mutbl: hir::Mutability::Mut }),
-        user_ty: UserTypeProjections::none(),
+    body.local_decls[SELF_ARG] = LocalDecl::with_source_info(
+        tcx.mk_ptr(ty::TypeAndMut { ty: gen_ty, mutbl: hir::Mutability::Mut }),
         source_info,
-        internal: false,
-        is_block_tail: None,
-        local_info: LocalInfo::Other,
-    };
+    );
     if tcx.sess.opts.debugging_opts.mir_emit_retag {
         // Alias tracking must know we changed the type
         body.basic_blocks_mut()[START_BLOCK].statements.insert(
@@ -922,7 +900,7 @@ fn create_generator_drop_shim<'tcx>(
 }
 
 fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> BasicBlock {
-    let source_info = source_info(body);
+    let source_info = SourceInfo::outermost(body.span);
     body.basic_blocks_mut().push(BasicBlockData {
         statements: Vec::new(),
         terminator: Some(Terminator { source_info, kind }),
@@ -948,7 +926,7 @@ fn insert_panic_block<'tcx>(
         cleanup: None,
     };
 
-    let source_info = source_info(body);
+    let source_info = SourceInfo::outermost(body.span);
     body.basic_blocks_mut().push(BasicBlockData {
         statements: Vec::new(),
         terminator: Some(Terminator { source_info, kind: term }),
@@ -1025,7 +1003,7 @@ fn create_generator_resume_function<'tcx>(
 
     // Poison the generator when it unwinds
     if can_unwind {
-        let source_info = source_info(body);
+        let source_info = SourceInfo::outermost(body.span);
         let poison_block = body.basic_blocks_mut().push(BasicBlockData {
             statements: vec![transform.set_discr(VariantIdx::new(POISONED), source_info)],
             terminator: Some(Terminator { source_info, kind: TerminatorKind::Resume }),
@@ -1092,10 +1070,6 @@ fn create_generator_resume_function<'tcx>(
     dump_mir(tcx, None, "generator_resume", &0, source, body, |_, _| Ok(()));
 }
 
-fn source_info(body: &Body<'_>) -> SourceInfo {
-    SourceInfo { span: body.span, scope: OUTERMOST_SOURCE_SCOPE }
-}
-
 fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock {
     let return_block = insert_term_block(body, TerminatorKind::Return);
 
@@ -1104,7 +1078,7 @@ fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock {
         target: return_block,
         unwind: None,
     };
-    let source_info = source_info(body);
+    let source_info = SourceInfo::outermost(body.span);
 
     // Create a block to destroy an unresumed generators. This can only destroy upvars.
     body.basic_blocks_mut().push(BasicBlockData {
@@ -1135,7 +1109,7 @@ fn create_cases<'tcx>(
     transform: &TransformVisitor<'tcx>,
     operation: Operation,
 ) -> Vec<(usize, BasicBlock)> {
-    let source_info = source_info(body);
+    let source_info = SourceInfo::outermost(body.span);
 
     transform
         .suspension_points
@@ -1241,7 +1215,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
             replace_local(resume_local, body.local_decls[resume_local].ty, body, tcx);
 
         // When first entering the generator, move the resume argument into its new local.
-        let source_info = source_info(body);
+        let source_info = SourceInfo::outermost(body.span);
         let stmts = &mut body.basic_blocks_mut()[BasicBlock::new(0)].statements;
         stmts.insert(
             0,
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 985bd2b1660..a8e949ecb31 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -480,7 +480,7 @@ impl Inliner<'tcx> {
 
                     let ty = dest.ty(caller_body, self.tcx);
 
-                    let temp = LocalDecl::new_temp(ty, callsite.location.span);
+                    let temp = LocalDecl::new(ty, callsite.location.span);
 
                     let tmp = caller_body.local_decls.push(temp);
                     let tmp = Place::from(tmp);
@@ -631,7 +631,7 @@ impl Inliner<'tcx> {
 
         let ty = arg.ty(caller_body, self.tcx);
 
-        let arg_tmp = LocalDecl::new_temp(ty, callsite.location.span);
+        let arg_tmp = LocalDecl::new(ty, callsite.location.span);
         let arg_tmp = caller_body.local_decls.push(arg_tmp);
 
         let stmt = Statement {
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 467e4188814..6dade3c8dca 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -778,7 +778,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
         self.promoted.basic_blocks_mut().push(BasicBlockData {
             statements: vec![],
             terminator: Some(Terminator {
-                source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
+                source_info: SourceInfo::outermost(span),
                 kind: TerminatorKind::Return,
             }),
             is_cleanup: false,
@@ -789,7 +789,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
         let last = self.promoted.basic_blocks().last().unwrap();
         let data = &mut self.promoted[last];
         data.statements.push(Statement {
-            source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
+            source_info: SourceInfo::outermost(span),
             kind: StatementKind::Assign(box (Place::from(dest), rvalue)),
         });
     }
@@ -818,7 +818,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
         }
 
         let num_stmts = self.source[loc.block].statements.len();
-        let new_temp = self.promoted.local_decls.push(LocalDecl::new_temp(
+        let new_temp = self.promoted.local_decls.push(LocalDecl::new(
             self.source.local_decls[temp].ty,
             self.source.local_decls[temp].source_info.span,
         ));
@@ -918,7 +918,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
             let tcx = self.tcx;
             let mut promoted_operand = |ty, span| {
                 promoted.span = span;
-                promoted.local_decls[RETURN_PLACE] = LocalDecl::new_return_place(ty, span);
+                promoted.local_decls[RETURN_PLACE] = LocalDecl::new(ty, span);
 
                 Operand::Constant(Box::new(Constant {
                     span,
@@ -966,7 +966,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                             // Create a temp to hold the promoted reference.
                             // This is because `*r` requires `r` to be a local,
                             // otherwise we would use the `promoted` directly.
-                            let mut promoted_ref = LocalDecl::new_temp(ref_ty, span);
+                            let mut promoted_ref = LocalDecl::new(ref_ty, span);
                             promoted_ref.source_info = statement.source_info;
                             let promoted_ref = local_decls.push(promoted_ref);
                             assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
@@ -1084,8 +1084,7 @@ pub fn promote_candidates<'tcx>(
         }
 
         // Declare return place local so that `mir::Body::new` doesn't complain.
-        let initial_locals =
-            iter::once(LocalDecl::new_return_place(tcx.types.never, body.span)).collect();
+        let initial_locals = iter::once(LocalDecl::new(tcx.types.never, body.span)).collect();
 
         let mut promoted = Body::new(
             IndexVec::new(),
diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs
index 9153f82588b..6566a996fe4 100644
--- a/src/librustc_mir/util/patch.rs
+++ b/src/librustc_mir/util/patch.rs
@@ -50,7 +50,7 @@ impl<'tcx> MirPatch<'tcx> {
             result.new_block(BasicBlockData {
                 statements: vec![],
                 terminator: Some(Terminator {
-                    source_info: SourceInfo { span: body.span, scope: OUTERMOST_SOURCE_SCOPE },
+                    source_info: SourceInfo::outermost(body.span),
                     kind: TerminatorKind::Resume,
                 }),
                 is_cleanup: true,
@@ -83,14 +83,14 @@ impl<'tcx> MirPatch<'tcx> {
     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, span));
+        self.new_locals.push(LocalDecl::new(ty, span));
         Local::new(index as usize)
     }
 
     pub fn new_internal(&mut self, ty: Ty<'tcx>, span: Span) -> Local {
         let index = self.next_local;
         self.next_local += 1;
-        self.new_locals.push(LocalDecl::new_internal(ty, span));
+        self.new_locals.push(LocalDecl::new(ty, span).internal());
         Local::new(index as usize)
     }
 
diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs
index 098601626db..090cd415437 100644
--- a/src/librustc_mir/util/pretty.rs
+++ b/src/librustc_mir/util/pretty.rs
@@ -472,8 +472,10 @@ fn write_scope_tree(
 
         let mut indented_decl =
             format!("{0:1$}let {2}{3:?}: {4:?}", INDENT, indent, mut_str, local, local_decl.ty);
-        for user_ty in local_decl.user_ty.projections() {
-            write!(indented_decl, " as {:?}", user_ty).unwrap();
+        if let Some(user_ty) = &local_decl.user_ty {
+            for user_ty in user_ty.projections() {
+                write!(indented_decl, " as {:?}", user_ty).unwrap();
+            }
         }
         indented_decl.push_str(";");
 
diff --git a/src/librustc_mir_build/build/expr/as_place.rs b/src/librustc_mir_build/build/expr/as_place.rs
index 9f74385b336..e08eedc6b6e 100644
--- a/src/librustc_mir_build/build/expr/as_place.rs
+++ b/src/librustc_mir_build/build/expr/as_place.rs
@@ -383,7 +383,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         let fake_borrow_ty =
                             tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
                         let fake_borrow_temp =
-                            self.local_decls.push(LocalDecl::new_temp(fake_borrow_ty, expr_span));
+                            self.local_decls.push(LocalDecl::new(fake_borrow_ty, expr_span));
                         let projection = tcx.intern_place_elems(&base_place.projection[..idx]);
                         self.cfg.push_assign(
                             block,
diff --git a/src/librustc_mir_build/build/expr/as_rvalue.rs b/src/librustc_mir_build/build/expr/as_rvalue.rs
index 38f71135c7d..d934ba1dc84 100644
--- a/src/librustc_mir_build/build/expr/as_rvalue.rs
+++ b/src/librustc_mir_build/build/expr/as_rvalue.rs
@@ -97,7 +97,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // The `Box<T>` temporary created here is not a part of the HIR,
                 // and therefore is not considered during generator OIBIT
                 // determination. See the comment about `box` at `yield_in_scope`.
-                let result = this.local_decls.push(LocalDecl::new_internal(expr.ty, expr_span));
+                let result = this.local_decls.push(LocalDecl::new(expr.ty, expr_span).internal());
                 this.cfg.push(
                     block,
                     Statement { source_info, kind: StatementKind::StorageLive(result) },
@@ -377,7 +377,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let this = self;
 
         let source_info = this.source_info(upvar_span);
-        let temp = this.local_decls.push(LocalDecl::new_temp(upvar_ty, upvar_span));
+        let temp = this.local_decls.push(LocalDecl::new(upvar_ty, upvar_span));
 
         this.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) });
 
diff --git a/src/librustc_mir_build/build/expr/as_temp.rs b/src/librustc_mir_build/build/expr/as_temp.rs
index d3304c71e61..d82abd87767 100644
--- a/src/librustc_mir_build/build/expr/as_temp.rs
+++ b/src/librustc_mir_build/build/expr/as_temp.rs
@@ -52,7 +52,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         let expr_ty = expr.ty;
         let temp = {
-            let mut local_decl = LocalDecl::new_temp(expr_ty, expr_span);
+            let mut local_decl = LocalDecl::new(expr_ty, expr_span);
             if mutability == Mutability::Not {
                 local_decl = local_decl.immutable();
             }
@@ -66,7 +66,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             if let ExprKind::StaticRef { def_id, .. } = expr.kind {
                 let is_thread_local = this.hir.tcx().is_thread_local_static(def_id);
                 local_decl.internal = true;
-                local_decl.local_info = LocalInfo::StaticRef { def_id, is_thread_local };
+                local_decl.local_info = Some(box LocalInfo::StaticRef { def_id, is_thread_local });
             }
             this.local_decls.push(local_decl)
         };
diff --git a/src/librustc_mir_build/build/expr/into.rs b/src/librustc_mir_build/build/expr/into.rs
index 52336b40a48..e26fb48a3f9 100644
--- a/src/librustc_mir_build/build/expr/into.rs
+++ b/src/librustc_mir_build/build/expr/into.rs
@@ -187,15 +187,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     let ptr_ty = ptr.ty;
                     // Create an *internal* temp for the pointer, so that unsafety
                     // checking won't complain about the raw pointer assignment.
-                    let ptr_temp = this.local_decls.push(LocalDecl {
-                        mutability: Mutability::Mut,
-                        ty: ptr_ty,
-                        user_ty: UserTypeProjections::none(),
+                    let ptr_temp = this.local_decls.push(LocalDecl::with_source_info(
+                        ptr_ty,
                         source_info,
-                        internal: true,
-                        local_info: LocalInfo::Other,
-                        is_block_tail: None,
-                    });
+                    ).internal());
                     let ptr_temp = Place::from(ptr_temp);
                     let block = unpack!(this.into(ptr_temp, block, ptr));
                     this.into(this.hir.tcx().mk_place_deref(ptr_temp), block, val)
@@ -348,7 +343,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // value is Sized. Usually, this is caught in type checking, but
                 // in the case of box expr there is no such check.
                 if !destination.projection.is_empty() {
-                    this.local_decls.push(LocalDecl::new_temp(expr.ty, expr.span));
+                    this.local_decls.push(LocalDecl::new(expr.ty, expr.span));
                 }
 
                 debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
diff --git a/src/librustc_mir_build/build/matches/mod.rs b/src/librustc_mir_build/build/matches/mod.rs
index b9d61458a83..f14de38a3f9 100644
--- a/src/librustc_mir_build/build/matches/mod.rs
+++ b/src/librustc_mir_build/build/matches/mod.rs
@@ -470,9 +470,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 for binding in &candidate_ref.bindings {
                     let local = self.var_local_id(binding.var_id, OutsideGuard);
 
-                    if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+                    if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
                         VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
-                    ))) = self.local_decls[local].local_info
+                    )))) = self.local_decls[local].local_info
                     {
                         *match_place = Some(initializer);
                     } else {
@@ -1539,7 +1539,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty;
                 let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
                 let fake_borrow_temp =
-                    self.local_decls.push(LocalDecl::new_temp(fake_borrow_ty, temp_span));
+                    self.local_decls.push(LocalDecl::new(fake_borrow_ty, temp_span));
 
                 (matched_place, fake_borrow_temp)
             })
@@ -1949,11 +1949,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let local = LocalDecl::<'tcx> {
             mutability,
             ty: var_ty,
-            user_ty,
+            user_ty: if user_ty.is_empty() { None } else { Some(box user_ty) },
             source_info,
             internal: false,
             is_block_tail: None,
-            local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+            local_info: Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
                 binding_mode,
                 // hypothetically, `visit_bindings` could try to unzip
                 // an outermost hir::Ty as we descend, matching up
@@ -1962,7 +1962,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 opt_ty_info: None,
                 opt_match_place,
                 pat_span,
-            }))),
+            })))),
         };
         let for_arm_body = self.local_decls.push(local);
         self.var_debug_info.push(VarDebugInfo {
@@ -1976,11 +1976,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // immutable to avoid the unused mut lint.
                 mutability: Mutability::Not,
                 ty: tcx.mk_imm_ref(tcx.lifetimes.re_erased, var_ty),
-                user_ty: UserTypeProjections::none(),
+                user_ty: None,
                 source_info,
                 internal: false,
                 is_block_tail: None,
-                local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)),
+                local_info: Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard))),
             });
             self.var_debug_info.push(VarDebugInfo {
                 name,
diff --git a/src/librustc_mir_build/build/misc.rs b/src/librustc_mir_build/build/misc.rs
index 578b862b905..e8933ff8aa7 100644
--- a/src/librustc_mir_build/build/misc.rs
+++ b/src/librustc_mir_build/build/misc.rs
@@ -15,7 +15,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// N.B., **No cleanup is scheduled for this temporary.** You should
     /// call `schedule_drop` once the temporary is initialized.
     crate fn temp(&mut self, ty: Ty<'tcx>, span: Span) -> Place<'tcx> {
-        let temp = self.local_decls.push(LocalDecl::new_temp(ty, span));
+        let temp = self.local_decls.push(LocalDecl::new(ty, span));
         let place = Place::from(temp);
         debug!("temp: created temp {:?} with type {:?}", place, self.local_decls[temp].ty);
         place
diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs
index 2ce2627987a..6c61c27c4ed 100644
--- a/src/librustc_mir_build/build/mod.rs
+++ b/src/librustc_mir_build/build/mod.rs
@@ -708,15 +708,7 @@ fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'t
     // Some MIR passes will expect the number of parameters to match the
     // function declaration.
     for _ in 0..num_params {
-        builder.local_decls.push(LocalDecl {
-            mutability: Mutability::Mut,
-            ty,
-            user_ty: UserTypeProjections::none(),
-            source_info,
-            internal: false,
-            local_info: LocalInfo::Other,
-            is_block_tail: None,
-        });
+        builder.local_decls.push(LocalDecl::with_source_info(ty, source_info));
     }
     builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
     let mut body = builder.finish();
@@ -750,10 +742,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             guard_context: vec![],
             push_unsafe_count: 0,
             unpushed_unsafe: safety,
-            local_decls: IndexVec::from_elem_n(
-                LocalDecl::new_return_place(return_ty, return_span),
-                1,
-            ),
+            local_decls: IndexVec::from_elem_n(LocalDecl::new(return_ty, return_span), 1),
             canonical_user_type_annotations: IndexVec::new(),
             upvar_mutbls: vec![],
             var_indices: Default::default(),
@@ -804,19 +793,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ) -> BlockAnd<()> {
         // Allocate locals for the function arguments
         for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() {
-            let source_info = SourceInfo {
-                scope: OUTERMOST_SOURCE_SCOPE,
-                span: arg_opt.map_or(self.fn_span, |arg| arg.pat.span),
-            };
-            let arg_local = self.local_decls.push(LocalDecl {
-                mutability: Mutability::Mut,
-                ty,
-                user_ty: UserTypeProjections::none(),
-                source_info,
-                internal: false,
-                local_info: LocalInfo::Other,
-                is_block_tail: None,
-            });
+            let source_info =
+                SourceInfo::outermost(arg_opt.map_or(self.fn_span, |arg| arg.pat.span));
+            let arg_local = self.local_decls.push(LocalDecl::with_source_info(ty, source_info));
 
             // If this is a simple binding pattern, give debuginfo a nice name.
             if let Some(arg) = arg_opt {
@@ -885,10 +864,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                     self.var_debug_info.push(VarDebugInfo {
                         name,
-                        source_info: SourceInfo {
-                            scope: OUTERMOST_SOURCE_SCOPE,
-                            span: tcx_hir.span(var_id),
-                        },
+                        source_info: SourceInfo::outermost(tcx_hir.span(var_id)),
                         place: Place {
                             local: closure_env_arg,
                             projection: tcx.intern_place_elems(&projs),
@@ -933,17 +909,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         self.local_decls[local].mutability = mutability;
                         self.local_decls[local].source_info.scope = self.source_scope;
                         self.local_decls[local].local_info = if let Some(kind) = self_binding {
-                            LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(*kind)))
+                            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(*kind))))
                         } else {
                             let binding_mode = ty::BindingMode::BindByValue(mutability);
-                            LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+                            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
                                 VarBindingForm {
                                     binding_mode,
                                     opt_ty_info,
                                     opt_match_place: Some((Some(place), span)),
                                     pat_span: span,
                                 },
-                            )))
+                            ))))
                         };
                         self.var_indices.insert(var, LocalsForNode::One(local));
                     }
diff --git a/src/librustc_mir_build/build/scope.rs b/src/librustc_mir_build/build/scope.rs
index d88cbf94513..4daf567d7d4 100644
--- a/src/librustc_mir_build/build/scope.rs
+++ b/src/librustc_mir_build/build/scope.rs
@@ -989,7 +989,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             let resumeblk = self.cfg.start_new_cleanup_block();
             self.cfg.terminate(
                 resumeblk,
-                SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span: self.fn_span },
+                SourceInfo::outermost(self.fn_span),
                 TerminatorKind::Resume,
             );
             self.cached_resume_block = Some(resumeblk);