about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/mir/repr.rs37
-rw-r--r--src/librustc/mir/visit.rs36
-rw-r--r--src/librustc_mir/build/block.rs39
-rw-r--r--src/librustc_mir/build/cfg.rs8
-rw-r--r--src/librustc_mir/build/expr/as_lvalue.rs2
-rw-r--r--src/librustc_mir/build/expr/as_operand.rs2
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs4
-rw-r--r--src/librustc_mir/build/expr/as_temp.rs2
-rw-r--r--src/librustc_mir/build/expr/into.rs2
-rw-r--r--src/librustc_mir/build/expr/stmt.rs2
-rw-r--r--src/librustc_mir/build/matches/mod.rs78
-rw-r--r--src/librustc_mir/build/misc.rs2
-rw-r--r--src/librustc_mir/build/mod.rs60
-rw-r--r--src/librustc_mir/build/scope.rs56
-rw-r--r--src/librustc_mir/pretty.rs136
-rw-r--r--src/librustc_mir/transform/promote_consts.rs6
-rw-r--r--src/librustc_trans/debuginfo/create_scope_map.rs14
-rw-r--r--src/librustc_trans/mir/mod.rs17
-rw-r--r--src/test/debuginfo/function-prologue-stepping-no-stack-check.rs13
19 files changed, 259 insertions, 257 deletions
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index 9666741d032..0d9c4646161 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -32,9 +32,9 @@ pub struct Mir<'tcx> {
     /// that indexes into this vector.
     pub basic_blocks: Vec<BasicBlockData<'tcx>>,
 
-    /// List of lexical scopes; these are referenced by statements and
-    /// used (eventually) for debuginfo. Indexed by a `ScopeId`.
-    pub scopes: Vec<ScopeData>,
+    /// List of visibility (lexical) scopes; these are referenced by statements
+    /// and used (eventually) for debuginfo. Indexed by a `VisibilityScope`.
+    pub visibility_scopes: Vec<VisibilityScopeData>,
 
     /// Rvalues promoted from this function, such as borrows of constants.
     /// Each of them is the Mir of a constant with the fn's type parameters
@@ -173,7 +173,7 @@ pub struct VarDecl<'tcx> {
     pub ty: Ty<'tcx>,
 
     /// scope in which variable was declared
-    pub scope: ScopeId,
+    pub scope: VisibilityScope,
 
     /// span where variable was declared
     pub span: Span,
@@ -276,7 +276,7 @@ pub struct BasicBlockData<'tcx> {
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub struct Terminator<'tcx> {
     pub span: Span,
-    pub scope: ScopeId,
+    pub scope: VisibilityScope,
     pub kind: TerminatorKind<'tcx>
 }
 
@@ -588,7 +588,7 @@ pub enum AssertMessage<'tcx> {
 #[derive(Clone, RustcEncodable, RustcDecodable)]
 pub struct Statement<'tcx> {
     pub span: Span,
-    pub scope: ScopeId,
+    pub scope: VisibilityScope,
     pub kind: StatementKind<'tcx>,
 }
 
@@ -754,29 +754,32 @@ impl<'tcx> Debug for Lvalue<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Scopes
 
-impl Index<ScopeId> for Vec<ScopeData> {
-    type Output = ScopeData;
+impl Index<VisibilityScope> for Vec<VisibilityScopeData> {
+    type Output = VisibilityScopeData;
 
     #[inline]
-    fn index(&self, index: ScopeId) -> &ScopeData {
+    fn index(&self, index: VisibilityScope) -> &VisibilityScopeData {
         &self[index.index()]
     }
 }
 
-impl IndexMut<ScopeId> for Vec<ScopeData> {
+impl IndexMut<VisibilityScope> for Vec<VisibilityScopeData> {
     #[inline]
-    fn index_mut(&mut self, index: ScopeId) -> &mut ScopeData {
+    fn index_mut(&mut self, index: VisibilityScope) -> &mut VisibilityScopeData {
         &mut self[index.index()]
     }
 }
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, RustcEncodable, RustcDecodable)]
-pub struct ScopeId(u32);
+pub struct VisibilityScope(u32);
 
-impl ScopeId {
-    pub fn new(index: usize) -> ScopeId {
+/// The visibility scope all arguments go into.
+pub const ARGUMENT_VISIBILITY_SCOPE: VisibilityScope = VisibilityScope(0);
+
+impl VisibilityScope {
+    pub fn new(index: usize) -> VisibilityScope {
         assert!(index < (u32::MAX as usize));
-        ScopeId(index as u32)
+        VisibilityScope(index as u32)
     }
 
     pub fn index(self) -> usize {
@@ -785,9 +788,9 @@ impl ScopeId {
 }
 
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
-pub struct ScopeData {
+pub struct VisibilityScopeData {
     pub span: Span,
-    pub parent_scope: Option<ScopeId>,
+    pub parent_scope: Option<VisibilityScope>,
 }
 
 ///////////////////////////////////////////////////////////////////////////
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 5c9582b945b..d340695761d 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -97,9 +97,9 @@ macro_rules! make_mir_visitor {
                 self.super_basic_block_data(block, data);
             }
 
-            fn visit_scope_data(&mut self,
-                                scope_data: & $($mutability)* ScopeData) {
-                self.super_scope_data(scope_data);
+            fn visit_visibility_scope_data(&mut self,
+                                           scope_data: & $($mutability)* VisibilityScopeData) {
+                self.super_visibility_scope_data(scope_data);
             }
 
             fn visit_statement(&mut self,
@@ -236,9 +236,9 @@ macro_rules! make_mir_visitor {
                 self.super_arg_decl(arg_decl);
             }
 
-            fn visit_scope_id(&mut self,
-                              scope_id: & $($mutability)* ScopeId) {
-                self.super_scope_id(scope_id);
+            fn visit_visibility_scope(&mut self,
+                                      scope: & $($mutability)* VisibilityScope) {
+                self.super_visibility_scope(scope);
             }
 
             // The `super_xxx` methods comprise the default behavior and are
@@ -248,7 +248,7 @@ macro_rules! make_mir_visitor {
                          mir: & $($mutability)* Mir<'tcx>) {
                 let Mir {
                     ref $($mutability)* basic_blocks,
-                    ref $($mutability)* scopes,
+                    ref $($mutability)* visibility_scopes,
                     promoted: _, // Visited by passes separately.
                     ref $($mutability)* return_ty,
                     ref $($mutability)* var_decls,
@@ -263,8 +263,8 @@ macro_rules! make_mir_visitor {
                     self.visit_basic_block_data(block, data);
                 }
 
-                for scope in scopes {
-                    self.visit_scope_data(scope);
+                for scope in visibility_scopes {
+                    self.visit_visibility_scope_data(scope);
                 }
 
                 self.visit_fn_output(return_ty);
@@ -302,16 +302,16 @@ macro_rules! make_mir_visitor {
                 }
             }
 
-            fn super_scope_data(&mut self,
-                                scope_data: & $($mutability)* ScopeData) {
-                let ScopeData {
+            fn super_visibility_scope_data(&mut self,
+                                           scope_data: & $($mutability)* VisibilityScopeData) {
+                let VisibilityScopeData {
                     ref $($mutability)* span,
                     ref $($mutability)* parent_scope,
                 } = *scope_data;
 
                 self.visit_span(span);
                 if let Some(ref $($mutability)* parent_scope) = *parent_scope {
-                    self.visit_scope_id(parent_scope);
+                    self.visit_visibility_scope(parent_scope);
                 }
             }
 
@@ -325,7 +325,7 @@ macro_rules! make_mir_visitor {
                 } = *statement;
 
                 self.visit_span(span);
-                self.visit_scope_id(scope);
+                self.visit_visibility_scope(scope);
                 match *kind {
                     StatementKind::Assign(ref $($mutability)* lvalue,
                                           ref $($mutability)* rvalue) => {
@@ -352,7 +352,7 @@ macro_rules! make_mir_visitor {
                 } = *terminator;
 
                 self.visit_span(span);
-                self.visit_scope_id(scope);
+                self.visit_visibility_scope(scope);
                 self.visit_terminator_kind(block, kind);
             }
 
@@ -627,7 +627,7 @@ macro_rules! make_mir_visitor {
                 } = *var_decl;
 
                 self.visit_ty(ty);
-                self.visit_scope_id(scope);
+                self.visit_visibility_scope(scope);
                 self.visit_span(span);
             }
 
@@ -651,8 +651,8 @@ macro_rules! make_mir_visitor {
                 self.visit_ty(ty);
             }
 
-            fn super_scope_id(&mut self,
-                              _scope_id: & $($mutability)* ScopeId) {
+            fn super_visibility_scope(&mut self,
+                                      _scope: & $($mutability)* VisibilityScope) {
             }
 
             fn super_branch(&mut self,
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index c1626b93f0c..f4e4b78b646 100644
--- a/src/librustc_mir/build/block.rs
+++ b/src/librustc_mir/build/block.rs
@@ -22,7 +22,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                      ast_block: &'tcx hir::Block)
                      -> BlockAnd<()> {
         let Block { extent, span, stmts, expr } = self.hir.mirror(ast_block);
-        self.in_scope(extent, block, move |this, _| {
+        self.in_scope(extent, block, move |this| {
             // This convoluted structure is to avoid using recursion as we walk down a list
             // of statements. Basically, the structure we get back is something like:
             //
@@ -40,27 +40,40 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             //
             // First we build all the statements in the block.
             let mut let_extent_stack = Vec::with_capacity(8);
+            let outer_visibility_scope = this.visibility_scope;
             for stmt in stmts {
                 let Stmt { span: _, kind } = this.hir.mirror(stmt);
                 match kind {
                     StmtKind::Expr { scope, expr } => {
-                        unpack!(block = this.in_scope(scope, block, |this, _| {
+                        unpack!(block = this.in_scope(scope, block, |this| {
                             let expr = this.hir.mirror(expr);
                             this.stmt_expr(block, expr)
                         }));
                     }
                     StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => {
-                        let remainder_scope_id = this.push_scope(remainder_scope, block);
+                        let tcx = this.hir.tcx();
+
+                        // Enter the remainder scope, i.e. the bindings' destruction scope.
+                        this.push_scope(remainder_scope, block);
                         let_extent_stack.push(remainder_scope);
-                        unpack!(block = this.in_scope(init_scope, block, move |this, _| {
-                            // FIXME #30046                              ^~~~
-                            if let Some(init) = initializer {
-                                this.expr_into_pattern(block, remainder_scope_id, pattern, init)
-                            } else {
-                                this.declare_bindings(remainder_scope_id, &pattern);
-                                block.unit()
-                            }
-                        }));
+
+                        // Declare the bindings, which may create a visibility scope.
+                        let remainder_span = remainder_scope.span(&tcx.region_maps, &tcx.map);
+                        let remainder_span = remainder_span.unwrap_or(span);
+                        let scope = this.declare_bindings(None, remainder_span, &pattern);
+
+                        // Evaluate the initializer, if present.
+                        if let Some(init) = initializer {
+                            unpack!(block = this.in_scope(init_scope, block, move |this| {
+                                // FIXME #30046                              ^~~~
+                                this.expr_into_pattern(block, pattern, init)
+                            }));
+                        }
+
+                        // Enter the visibility scope, after evaluating the initializer.
+                        if let Some(visibility_scope) = scope {
+                            this.visibility_scope = visibility_scope;
+                        }
                     }
                 }
             }
@@ -78,6 +91,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             for extent in let_extent_stack.into_iter().rev() {
                 unpack!(block = this.pop_scope(extent, block));
             }
+            // Restore the original visibility scope.
+            this.visibility_scope = outer_visibility_scope;
             block.unit()
         })
     }
diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs
index 4859257f291..4045497575d 100644
--- a/src/librustc_mir/build/cfg.rs
+++ b/src/librustc_mir/build/cfg.rs
@@ -50,7 +50,7 @@ impl<'tcx> CFG<'tcx> {
 
     pub fn push_assign(&mut self,
                        block: BasicBlock,
-                       scope: ScopeId,
+                       scope: VisibilityScope,
                        span: Span,
                        lvalue: &Lvalue<'tcx>,
                        rvalue: Rvalue<'tcx>) {
@@ -63,7 +63,7 @@ impl<'tcx> CFG<'tcx> {
 
     pub fn push_assign_constant(&mut self,
                                 block: BasicBlock,
-                                scope: ScopeId,
+                                scope: VisibilityScope,
                                 span: Span,
                                 temp: &Lvalue<'tcx>,
                                 constant: Constant<'tcx>) {
@@ -73,7 +73,7 @@ impl<'tcx> CFG<'tcx> {
 
     pub fn push_assign_unit(&mut self,
                             block: BasicBlock,
-                            scope: ScopeId,
+                            scope: VisibilityScope,
                             span: Span,
                             lvalue: &Lvalue<'tcx>) {
         self.push_assign(block, scope, span, lvalue, Rvalue::Aggregate(
@@ -83,7 +83,7 @@ impl<'tcx> CFG<'tcx> {
 
     pub fn terminate(&mut self,
                      block: BasicBlock,
-                     scope: ScopeId,
+                     scope: VisibilityScope,
                      span: Span,
                      kind: TerminatorKind<'tcx>) {
         debug_assert!(self.block_data(block).terminator.is_none(),
diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs
index bb5aca2d8d7..1f78071dfce 100644
--- a/src/librustc_mir/build/expr/as_lvalue.rs
+++ b/src/librustc_mir/build/expr/as_lvalue.rs
@@ -38,7 +38,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let expr_span = expr.span;
         match expr.kind {
             ExprKind::Scope { extent, value } => {
-                this.in_scope(extent, block, |this, _| this.as_lvalue(block, value))
+                this.in_scope(extent, block, |this| this.as_lvalue(block, value))
             }
             ExprKind::Field { lhs, name } => {
                 let lvalue = unpack!(block = this.as_lvalue(block, lhs));
diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs
index a059f2bdde9..beb9ca256ab 100644
--- a/src/librustc_mir/build/expr/as_operand.rs
+++ b/src/librustc_mir/build/expr/as_operand.rs
@@ -35,7 +35,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let this = self;
 
         if let ExprKind::Scope { extent, value } = expr.kind {
-            return this.in_scope(extent, block, |this, _| this.as_operand(block, value));
+            return this.in_scope(extent, block, |this| this.as_operand(block, value));
         }
 
         let category = Category::of(&expr.kind).unwrap();
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 67cf5473f79..19a3bc4d0e9 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -46,7 +46,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         match expr.kind {
             ExprKind::Scope { extent, value } => {
-                this.in_scope(extent, block, |this, _| this.as_rvalue(block, value))
+                this.in_scope(extent, block, |this| this.as_rvalue(block, value))
             }
             ExprKind::InlineAsm { asm, outputs, inputs } => {
                 let outputs = outputs.into_iter().map(|output| {
@@ -100,7 +100,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let result = this.temp(expr.ty);
                 // to start, malloc some memory of suitable type (thus far, uninitialized):
                 this.cfg.push_assign(block, scope_id, expr_span, &result, Rvalue::Box(value.ty));
-                this.in_scope(value_extents, block, |this, _| {
+                this.in_scope(value_extents, block, |this| {
                     // schedule a shallow free of that memory, lest we unwind:
                     this.schedule_box_free(expr_span, value_extents, &result, value.ty);
                     // initialize the box contents:
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index f33d3dd5190..2a28f331801 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -30,7 +30,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let this = self;
 
         if let ExprKind::Scope { extent, value } = expr.kind {
-            return this.in_scope(extent, block, |this, _| this.as_temp(block, value));
+            return this.in_scope(extent, block, |this| this.as_temp(block, value));
         }
 
         let expr_ty = expr.ty.clone();
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 41610c90377..fb77fc50f86 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -37,7 +37,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         match expr.kind {
             ExprKind::Scope { extent, value } => {
-                this.in_scope(extent, block, |this, _| this.into(destination, block, value))
+                this.in_scope(extent, block, |this| this.into(destination, block, value))
             }
             ExprKind::Block { body: ast_block } => {
                 this.ast_block(destination, expr.ty.is_nil(), block, ast_block)
diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs
index 24369aaff3f..add268d394a 100644
--- a/src/librustc_mir/build/expr/stmt.rs
+++ b/src/librustc_mir/build/expr/stmt.rs
@@ -26,7 +26,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         match expr.kind {
             ExprKind::Scope { extent, value } => {
                 let value = this.hir.mirror(value);
-                this.in_scope(extent, block, |this, _| this.stmt_expr(block, value))
+                this.in_scope(extent, block, |this| this.stmt_expr(block, value))
             }
             ExprKind::Assign { lhs, rhs } => {
                 let lhs = this.hir.mirror(lhs);
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 88d7e41bc61..46c907009a3 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -44,21 +44,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         .collect(),
         };
 
-        // Get the body expressions and their scopes, while declaring bindings.
-        let arm_bodies: Vec<_> = arms.iter().enumerate().map(|(i, arm)| {
-            // Assume that all expressions are wrapped in Scope.
+        // Get the arm bodies and their scopes, while declaring bindings.
+        let arm_bodies: Vec<_> = arms.iter().map(|arm| {
             let body = self.hir.mirror(arm.body.clone());
-            match body.kind {
-                ExprKind::Scope { extent, value } => {
-                    let scope_id = self.push_scope(extent, arm_blocks.blocks[i]);
-                    self.declare_bindings(scope_id, &arm.patterns[0]);
-                    (extent, self.scopes.pop().unwrap(), value)
-                }
-                _ => {
-                    span_bug!(body.span, "arm body is not wrapped in Scope {:?}",
-                              body.kind);
-                }
-            }
+            let scope = self.declare_bindings(None, body.span, &arm.patterns[0]);
+            (body, scope.unwrap_or(self.visibility_scope))
         }).collect();
 
         // assemble a list of candidates: there is one candidate per
@@ -99,63 +89,48 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         // all the arm blocks will rejoin here
         let end_block = self.cfg.start_new_block();
 
-        let scope_id = self.innermost_scope_id();
-        for (arm_index, (extent, scope, body)) in arm_bodies.into_iter().enumerate() {
+        let outer_visibility_scope = self.innermost_scope_id();
+        for (arm_index, (body, visibility_scope)) in arm_bodies.into_iter().enumerate() {
             let mut arm_block = arm_blocks.blocks[arm_index];
-            // Re-enter the scope we created the bindings in.
-            self.scopes.push(scope);
+            // Re-enter the visibility scope we created the bindings in.
+            self.visibility_scope = visibility_scope;
             unpack!(arm_block = self.into(destination, arm_block, body));
-            unpack!(arm_block = self.pop_scope(extent, arm_block));
             self.cfg.terminate(arm_block,
-                               scope_id,
+                               outer_visibility_scope,
                                span,
                                TerminatorKind::Goto { target: end_block });
         }
+        self.visibility_scope = outer_visibility_scope;
 
         end_block.unit()
     }
 
     pub fn expr_into_pattern(&mut self,
                              mut block: BasicBlock,
-                             var_scope_id: ScopeId, // lifetime of vars
                              irrefutable_pat: Pattern<'tcx>,
                              initializer: ExprRef<'tcx>)
                              -> BlockAnd<()> {
         // optimize the case of `let x = ...`
         match *irrefutable_pat.kind {
-            PatternKind::Binding { mutability,
-                                   name,
-                                   mode: BindingMode::ByValue,
+            PatternKind::Binding { mode: BindingMode::ByValue,
                                    var,
-                                   ty,
-                                   subpattern: None } => {
-                let index = self.declare_binding(var_scope_id,
-                                                 mutability,
-                                                 name,
-                                                 var,
-                                                 ty,
-                                                 irrefutable_pat.span);
-                let lvalue = Lvalue::Var(index);
+                                   subpattern: None, .. } => {
+                let lvalue = Lvalue::Var(self.var_indices[&var]);
                 return self.into(&lvalue, block, initializer);
             }
             _ => {}
         }
         let lvalue = unpack!(block = self.as_lvalue(block, initializer));
         self.lvalue_into_pattern(block,
-                                 var_scope_id,
                                  irrefutable_pat,
                                  &lvalue)
     }
 
     pub fn lvalue_into_pattern(&mut self,
                                mut block: BasicBlock,
-                               var_scope_id: ScopeId,
                                irrefutable_pat: Pattern<'tcx>,
                                initializer: &Lvalue<'tcx>)
                                -> BlockAnd<()> {
-        // first, creating the bindings
-        self.declare_bindings(var_scope_id, &irrefutable_pat);
-
         // create a dummy candidate
         let mut candidate = Candidate {
             span: irrefutable_pat.span,
@@ -182,32 +157,43 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         block.unit()
     }
 
-    pub fn declare_bindings(&mut self, var_scope_id: ScopeId, pattern: &Pattern<'tcx>) {
+    /// Declares the bindings of the given pattern and returns the visibility scope
+    /// for the bindings in this patterns, if such a scope had to be created.
+    /// NOTE: Declaring the bindings should always be done in their drop scope.
+    pub fn declare_bindings(&mut self,
+                            mut var_scope: Option<VisibilityScope>,
+                            scope_span: Span,
+                            pattern: &Pattern<'tcx>)
+                            -> Option<VisibilityScope> {
         match *pattern.kind {
             PatternKind::Binding { mutability, name, mode: _, var, ty, ref subpattern } => {
-                self.declare_binding(var_scope_id, mutability, name, var, ty, pattern.span);
+                if var_scope.is_none() {
+                    var_scope = Some(self.new_visibility_scope(scope_span));
+                }
+                self.declare_binding(var_scope.unwrap(), mutability, name, var, ty, pattern.span);
                 if let Some(subpattern) = subpattern.as_ref() {
-                    self.declare_bindings(var_scope_id, subpattern);
+                    var_scope = self.declare_bindings(var_scope, scope_span, subpattern);
                 }
             }
             PatternKind::Array { ref prefix, ref slice, ref suffix } |
             PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
                 for subpattern in prefix.iter().chain(slice).chain(suffix) {
-                    self.declare_bindings(var_scope_id, subpattern);
+                    var_scope = self.declare_bindings(var_scope, scope_span, subpattern);
                 }
             }
             PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
             }
             PatternKind::Deref { ref subpattern } => {
-                self.declare_bindings(var_scope_id, subpattern);
+                var_scope = self.declare_bindings(var_scope, scope_span, subpattern);
             }
             PatternKind::Leaf { ref subpatterns } |
             PatternKind::Variant { ref subpatterns, .. } => {
                 for subpattern in subpatterns {
-                    self.declare_bindings(var_scope_id, &subpattern.pattern);
+                    var_scope = self.declare_bindings(var_scope, scope_span, &subpattern.pattern);
                 }
             }
         }
+        var_scope
     }
 }
 
@@ -635,7 +621,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     }
 
     fn declare_binding(&mut self,
-                       var_scope_id: ScopeId,
+                       var_scope_id: VisibilityScope,
                        mutability: Mutability,
                        name: Name,
                        var_id: NodeId,
@@ -655,7 +641,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             span: span,
         });
         let index = index as u32;
-        let extent = self.scope_auxiliary[var_scope_id].extent;
+        let extent = self.extent_of_innermost_scope();
         self.schedule_drop(span, extent, &Lvalue::Var(index), var_ty);
         self.var_indices.insert(var_id, index);
 
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index c3501140fc0..a6294406ea5 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -103,7 +103,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     pub fn push_usize(&mut self,
                       block: BasicBlock,
-                      scope_id: ScopeId,
+                      scope_id: VisibilityScope,
                       span: Span,
                       value: u64)
                       -> Lvalue<'tcx> {
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 9d7818a9ba4..27cced2ae1a 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -15,6 +15,7 @@ use rustc::mir::repr::*;
 use rustc_data_structures::fnv::FnvHashMap;
 use rustc::hir;
 use std::ops::{Index, IndexMut};
+use std::u32;
 use syntax::abi::Abi;
 use syntax::ast;
 use syntax::codemap::Span;
@@ -43,7 +44,8 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
     /// the vector of all scopes that we have created thus far;
     /// we track this for debuginfo later
-    scope_datas: Vec<ScopeData>,
+    visibility_scopes: Vec<VisibilityScopeData>,
+    visibility_scope: VisibilityScope,
 
     var_decls: Vec<VarDecl<'tcx>>,
     var_indices: FnvHashMap<ast::NodeId, u32>,
@@ -61,6 +63,20 @@ struct CFG<'tcx> {
     basic_blocks: Vec<BasicBlockData<'tcx>>,
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct ScopeId(u32);
+
+impl ScopeId {
+    pub fn new(index: usize) -> ScopeId {
+        assert!(index < (u32::MAX as usize));
+        ScopeId(index as u32)
+    }
+
+    pub fn index(self) -> usize {
+        self.0 as usize
+    }
+}
+
 /// For each scope, we track the extent (from the HIR) and a
 /// single-entry-multiple-exit subgraph that contains all the
 /// statements/terminators within it.
@@ -179,17 +195,16 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
         tcx.region_maps.lookup_code_extent(
             CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
     let mut block = START_BLOCK;
-    let mut arg_decls = unpack!(block = builder.in_scope(call_site_extent, block,
-                                                         |builder, call_site_scope_id| {
-        let arg_decls = unpack!(block = builder.in_scope(arg_extent, block,
-                                                         |builder, arg_scope_id| {
-            builder.args_and_body(block, return_ty, arguments, arg_scope_id, ast_block)
+    let mut arg_decls = unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
+        let arg_decls = unpack!(block = builder.in_scope(arg_extent, block, |builder| {
+            builder.args_and_body(block, return_ty, arguments, arg_extent, ast_block)
         }));
 
+        let visibility_scope = builder.visibility_scope;
         let return_block = builder.return_block();
-        builder.cfg.terminate(block, call_site_scope_id, span,
+        builder.cfg.terminate(block, visibility_scope, span,
                               TerminatorKind::Goto { target: return_block });
-        builder.cfg.terminate(return_block, call_site_scope_id, span,
+        builder.cfg.terminate(return_block, visibility_scope, span,
                               TerminatorKind::Return);
         return_block.and(arg_decls)
     }));
@@ -241,14 +256,15 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
 
     let extent = ROOT_CODE_EXTENT;
     let mut block = START_BLOCK;
-    let _ = builder.in_scope(extent, block, |builder, call_site_scope_id| {
+    let _ = builder.in_scope(extent, block, |builder| {
         let expr = builder.hir.mirror(ast_expr);
         unpack!(block = builder.into(&Lvalue::ReturnPointer, block, expr));
 
+        let visibility_scope = builder.visibility_scope;
         let return_block = builder.return_block();
-        builder.cfg.terminate(block, call_site_scope_id, span,
+        builder.cfg.terminate(block, visibility_scope, span,
                               TerminatorKind::Goto { target: return_block });
-        builder.cfg.terminate(return_block, call_site_scope_id, span,
+        builder.cfg.terminate(return_block, visibility_scope, span,
                               TerminatorKind::Return);
 
         return_block.unit()
@@ -265,7 +281,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             cfg: CFG { basic_blocks: vec![] },
             fn_span: span,
             scopes: vec![],
-            scope_datas: vec![],
+            visibility_scopes: vec![],
+            visibility_scope: ARGUMENT_VISIBILITY_SCOPE,
             scope_auxiliary: ScopeAuxiliaryVec { vec: vec![] },
             loop_scopes: vec![],
             temp_decls: vec![],
@@ -277,6 +294,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         };
 
         assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
+        assert_eq!(builder.new_visibility_scope(span), ARGUMENT_VISIBILITY_SCOPE);
+        builder.visibility_scopes[ARGUMENT_VISIBILITY_SCOPE].parent_scope = None;
 
         builder
     }
@@ -294,7 +313,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         (Mir {
             basic_blocks: self.cfg.basic_blocks,
-            scopes: self.scope_datas,
+            visibility_scopes: self.visibility_scopes,
             promoted: vec![],
             var_decls: self.var_decls,
             arg_decls: arg_decls,
@@ -309,24 +328,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         mut block: BasicBlock,
                         return_ty: ty::FnOutput<'tcx>,
                         arguments: A,
-                        argument_scope_id: ScopeId,
+                        argument_extent: CodeExtent,
                         ast_block: &'gcx hir::Block)
                         -> BlockAnd<Vec<ArgDecl<'tcx>>>
         where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
     {
         // to start, translate the argument patterns and collect the argument types.
+        let mut scope = None;
         let arg_decls = arguments.enumerate().map(|(index, (ty, pattern))| {
             let lvalue = Lvalue::Arg(index as u32);
             if let Some(pattern) = pattern {
                 let pattern = self.hir.irrefutable_pat(pattern);
-                unpack!(block = self.lvalue_into_pattern(block,
-                                                         argument_scope_id,
-                                                         pattern,
-                                                         &lvalue));
+                scope = self.declare_bindings(scope, ast_block.span, &pattern);
+                unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue));
             }
 
             // Make sure we drop (parts of) the argument even when not matched on.
-            let argument_extent = self.scope_auxiliary[argument_scope_id].extent;
             self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
                                argument_extent, &lvalue, ty);
 
@@ -344,6 +361,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
         }).collect();
 
+        // Enter the argument pattern bindings visibility scope, if it exists.
+        if let Some(visibility_scope) = scope {
+            self.visibility_scope = visibility_scope;
+        }
+
         // FIXME(#32959): temporary hack for the issue at hand
         let return_is_unit = if let ty::FnConverging(t) = return_ty {
             t.is_nil()
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 209649dd2fd..93ca01ba2ec 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -86,7 +86,7 @@ should go to.
 
 */
 
-use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary};
+use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary, ScopeId};
 use rustc::middle::region::{CodeExtent, CodeExtentData};
 use rustc::middle::lang_items;
 use rustc::ty::subst::{Substs, Subst, VecPerParamSpace};
@@ -98,9 +98,12 @@ use rustc::middle::const_val::ConstVal;
 use rustc_const_math::ConstInt;
 
 pub struct Scope<'tcx> {
-    /// the scope-id within the scope_datas
+    /// the scope-id within the scope_auxiliary
     id: ScopeId,
 
+    /// The visibility scope this scope was created in.
+    visibility_scope: VisibilityScope,
+
     /// the extent of this scope within source code; also stored in
     /// `ScopeAuxiliary`, but kept here for convenience
     extent: CodeExtent,
@@ -237,11 +240,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Convenience wrapper that pushes a scope and then executes `f`
     /// to build its contents, popping the scope afterwards.
     pub fn in_scope<F, R>(&mut self, extent: CodeExtent, mut block: BasicBlock, f: F) -> BlockAnd<R>
-        where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>, ScopeId) -> BlockAnd<R>
+        where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd<R>
     {
         debug!("in_scope(extent={:?}, block={:?})", extent, block);
-        let id = self.push_scope(extent, block);
-        let rv = unpack!(block = f(self, id));
+        self.push_scope(extent, block);
+        let rv = unpack!(block = f(self));
         unpack!(block = self.pop_scope(extent, block));
         debug!("in_scope: exiting extent={:?} block={:?}", extent, block);
         block.and(rv)
@@ -251,17 +254,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// scope and call `pop_scope` afterwards. Note that these two
     /// calls must be paired; using `in_scope` as a convenience
     /// wrapper maybe preferable.
-    pub fn push_scope(&mut self, extent: CodeExtent, entry: BasicBlock) -> ScopeId {
+    pub fn push_scope(&mut self, extent: CodeExtent, entry: BasicBlock) {
         debug!("push_scope({:?})", extent);
-        let parent_id = self.scopes.last().map(|s| s.id);
-        let id = ScopeId::new(self.scope_datas.len());
-        let tcx = self.hir.tcx();
-        self.scope_datas.push(ScopeData {
-            span: extent.span(&tcx.region_maps, &tcx.map).unwrap_or(DUMMY_SP),
-            parent_scope: parent_id,
-        });
+        let id = ScopeId::new(self.scope_auxiliary.vec.len());
+        let vis_scope = self.visibility_scope;
         self.scopes.push(Scope {
             id: id,
+            visibility_scope: vis_scope,
             extent: extent,
             drops: vec![],
             free: None,
@@ -272,7 +271,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             dom: self.cfg.current_location(entry),
             postdoms: vec![]
         });
-        id
     }
 
     /// Pops a scope, which should have extent `extent`, adding any
@@ -320,7 +318,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             if let Some(ref free_data) = scope.free {
                 let next = self.cfg.start_new_block();
                 let free = build_free(self.hir.tcx(), &tmp, free_data, next);
-                self.cfg.terminate(block, scope.id, span, free);
+                self.cfg.terminate(block, scope.visibility_scope, span, free);
                 block = next;
             }
             self.scope_auxiliary[scope.id]
@@ -334,11 +332,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                             .next()
                                             .unwrap();
         self.cfg.terminate(block,
-                           scope.id,
+                           scope.visibility_scope,
                            span,
                            TerminatorKind::Goto { target: target });
     }
 
+    /// Creates a new visibility scope, nested in the current one.
+    pub fn new_visibility_scope(&mut self, span: Span) -> VisibilityScope {
+        let parent = self.visibility_scope;
+        let scope = VisibilityScope::new(self.visibility_scopes.len());
+        self.visibility_scopes.push(VisibilityScopeData {
+            span: span,
+            parent_scope: Some(parent),
+        });
+        scope
+    }
+
     // Finding scopes
     // ==============
     /// Finds the loop scope for a given label. This is used for
@@ -363,8 +372,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         }.unwrap_or_else(|| span_bug!(span, "no enclosing loop scope found?"))
     }
 
-    pub fn innermost_scope_id(&self) -> ScopeId {
-        self.scopes.last().map(|scope| scope.id).unwrap()
+    pub fn innermost_scope_id(&self) -> VisibilityScope {
+        self.visibility_scope
     }
 
     pub fn extent_of_innermost_scope(&self) -> CodeExtent {
@@ -481,7 +490,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             target
         } else {
             let resumeblk = cfg.start_new_cleanup_block();
-            cfg.terminate(resumeblk, scopes[0].id, self.fn_span, TerminatorKind::Resume);
+            cfg.terminate(resumeblk,
+                          scopes[0].visibility_scope,
+                          self.fn_span,
+                          TerminatorKind::Resume);
             *cached_resume_block = Some(resumeblk);
             resumeblk
         };
@@ -658,7 +670,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
             earlier_scopes.iter().rev().flat_map(|s| s.cached_block()).next()
         });
         let next = cfg.start_new_block();
-        cfg.terminate(block, scope.id, drop_data.span, TerminatorKind::Drop {
+        cfg.terminate(block, scope.visibility_scope, drop_data.span, TerminatorKind::Drop {
             location: drop_data.location.clone(),
             target: next,
             unwind: on_diverge
@@ -695,7 +707,7 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         } else {
             let into = cfg.start_new_cleanup_block();
             cfg.terminate(into,
-                          scope.id,
+                          scope.visibility_scope,
                           free_data.span,
                           build_free(tcx, unit_temp, free_data, target));
             free_data.cached_block = Some(into);
@@ -712,7 +724,7 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         } else {
             let block = cfg.start_new_cleanup_block();
             cfg.terminate(block,
-                          scope.id,
+                          scope.visibility_scope,
                           drop_data.span,
                           TerminatorKind::Drop {
                               location: drop_data.location.clone(),
diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs
index a6bbd55ffa7..5849db6bbd2 100644
--- a/src/librustc_mir/pretty.rs
+++ b/src/librustc_mir/pretty.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use build::{Location, ScopeAuxiliaryVec};
+use build::{Location, ScopeAuxiliaryVec, ScopeId};
 use rustc::hir;
 use rustc::mir::repr::*;
 use rustc::mir::transform::MirSource;
@@ -139,20 +139,11 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     write_mir_intro(tcx, src, mir, w)?;
     for block in mir.all_basic_blocks() {
         write_basic_block(tcx, block, mir, w, &annotations)?;
+        if block.index() + 1 != mir.basic_blocks.len() {
+            writeln!(w, "")?;
+        }
     }
 
-    // construct a scope tree and write it out
-    let mut scope_tree: FnvHashMap<Option<ScopeId>, Vec<ScopeId>> = FnvHashMap();
-    for (index, scope_data) in mir.scopes.iter().enumerate() {
-        scope_tree.entry(scope_data.parent_scope)
-                  .or_insert(vec![])
-                  .push(ScopeId::new(index));
-    }
-
-    writeln!(w, "{}scope tree:", INDENT)?;
-    write_scope_tree(tcx, mir, auxiliary, &scope_tree, w, None, 1, false)?;
-    writeln!(w, "")?;
-
     writeln!(w, "}}")?;
     Ok(())
 }
@@ -204,66 +195,59 @@ fn write_basic_block(tcx: TyCtxt,
     writeln!(w, "{}}}\n", INDENT)
 }
 
-fn comment(tcx: TyCtxt, scope: ScopeId, span: Span) -> String {
+fn comment(tcx: TyCtxt, scope: VisibilityScope, span: Span) -> String {
     format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
 }
 
 fn write_scope_tree(tcx: TyCtxt,
                     mir: &Mir,
-                    auxiliary: Option<&ScopeAuxiliaryVec>,
-                    scope_tree: &FnvHashMap<Option<ScopeId>, Vec<ScopeId>>,
+                    scope_tree: &FnvHashMap<VisibilityScope, Vec<VisibilityScope>>,
                     w: &mut Write,
-                    parent: Option<ScopeId>,
-                    depth: usize,
-                    same_line: bool)
+                    parent: VisibilityScope,
+                    depth: usize)
                     -> io::Result<()> {
-    let indent = if same_line {
-        0
-    } else {
-        depth * INDENT.len()
-    };
+    let indent = depth * INDENT.len();
 
     let children = match scope_tree.get(&parent) {
         Some(childs) => childs,
         None => return Ok(()),
     };
 
-    for (index, &child) in children.iter().enumerate() {
-        if index == 0 && same_line {
-            // We know we're going to output a scope, so prefix it with a space to separate it from
-            // the previous scopes on this line
-            write!(w, " ")?;
-        }
-
-        let data = &mir.scopes[child];
-        assert_eq!(data.parent_scope, parent);
-        write!(w, "{0:1$}{2}", "", indent, child.index())?;
+    for &child in children {
+        let data = &mir.visibility_scopes[child];
+        assert_eq!(data.parent_scope, Some(parent));
+        writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;
 
-        let indent = indent + INDENT.len();
+        // User variable types (including the user's name in a comment).
+        for (i, var) in mir.var_decls.iter().enumerate() {
+            // Skip if not declared in this scope.
+            if var.scope != child {
+                continue;
+            }
 
-        if let Some(auxiliary) = auxiliary {
-            let extent = auxiliary[child].extent;
-            let data = tcx.region_maps.code_extent_data(extent);
-            writeln!(w, "{0:1$}Extent: {2:?}", "", indent, data)?;
+            let mut_str = if var.mutability == Mutability::Mut {
+                "mut "
+            } else {
+                ""
+            };
+
+            let indent = indent + INDENT.len();
+            let indented_var = format!("{0:1$}let {2}{3:?}: {4};",
+                                       INDENT,
+                                       indent,
+                                       mut_str,
+                                       Lvalue::Var(i as u32),
+                                       var.ty);
+            writeln!(w, "{0:1$} // \"{2}\" in {3}",
+                     indented_var,
+                     ALIGN,
+                     var.name,
+                     comment(tcx, var.scope, var.span))?;
         }
 
-        let child_count = scope_tree.get(&Some(child)).map(Vec::len).unwrap_or(0);
-        if child_count < 2 {
-            // Skip the braces when there's no or only a single subscope
-            write_scope_tree(tcx, mir, auxiliary, scope_tree, w,
-                             Some(child), depth, true)?;
-        } else {
-            // 2 or more child scopes? Put them in braces and on new lines.
-            writeln!(w, " {{")?;
-            write_scope_tree(tcx, mir, auxiliary, scope_tree, w,
-                             Some(child), depth + 1, false)?;
-
-            write!(w, "\n{0:1$}}}", "", depth * INDENT.len())?;
-        }
+        write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?;
 
-        if !same_line && index + 1 < children.len() {
-            writeln!(w, "")?;
-        }
+        writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?;
     }
 
     Ok(())
@@ -278,7 +262,23 @@ fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              -> io::Result<()> {
     write_mir_sig(tcx, src, mir, w)?;
     writeln!(w, " {{")?;
-    write_mir_decls(tcx, mir, w)
+
+    // construct a scope tree and write it out
+    let mut scope_tree: FnvHashMap<VisibilityScope, Vec<VisibilityScope>> = FnvHashMap();
+    for (index, scope_data) in mir.visibility_scopes.iter().enumerate() {
+        if let Some(parent) = scope_data.parent_scope {
+            scope_tree.entry(parent)
+                      .or_insert(vec![])
+                      .push(VisibilityScope::new(index));
+        } else {
+            // Only the argument scope has no parent, because it's the root.
+            assert_eq!(index, ARGUMENT_VISIBILITY_SCOPE.index());
+        }
+    }
+
+    write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?;
+
+    write_mir_decls(mir, w)
 }
 
 fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
@@ -318,29 +318,7 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
     }
 }
 
-fn write_mir_decls(tcx: TyCtxt, mir: &Mir, w: &mut Write)
-                   -> io::Result<()>
-{
-    // User variable types (including the user's name in a comment).
-    for (i, var) in mir.var_decls.iter().enumerate() {
-        let mut_str = if var.mutability == Mutability::Mut {
-            "mut "
-        } else {
-            ""
-        };
-
-        let indented_var = format!("{}let {}{:?}: {};",
-                                   INDENT,
-                                   mut_str,
-                                   Lvalue::Var(i as u32),
-                                   var.ty);
-        writeln!(w, "{0:1$} // \"{2}\" in {3}",
-                 indented_var,
-                 ALIGN,
-                 var.name,
-                 comment(tcx, var.scope, var.span))?;
-    }
-
+fn write_mir_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
     // Compiler-introduced temporary types.
     for (i, temp) in mir.temp_decls.iter().enumerate() {
         writeln!(w, "{}let mut {:?}: {};", INDENT, Lvalue::Temp(i as u32), temp.ty)?;
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index d81c4e2dfb6..0a533d6e289 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -168,7 +168,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
             statements: vec![],
             terminator: Some(Terminator {
                 span: self.promoted.span,
-                scope: ScopeId::new(0),
+                scope: VisibilityScope::new(0),
                 kind: TerminatorKind::Return
             }),
             is_cleanup: false
@@ -180,7 +180,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
         let data = self.promoted.basic_blocks.last_mut().unwrap();
         data.statements.push(Statement {
             span: span,
-            scope: ScopeId::new(0),
+            scope: VisibilityScope::new(0),
             kind: StatementKind::Assign(dest, rvalue)
         });
     }
@@ -367,7 +367,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
             source: mir,
             promoted: Mir {
                 basic_blocks: vec![],
-                scopes: vec![ScopeData {
+                visibility_scopes: vec![VisibilityScopeData {
                     span: span,
                     parent_scope: None
                 }],
diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs
index bba0edd5f04..2c23be02ddc 100644
--- a/src/librustc_trans/debuginfo/create_scope_map.rs
+++ b/src/librustc_trans/debuginfo/create_scope_map.rs
@@ -16,7 +16,7 @@ use llvm;
 use llvm::debuginfo::{DIScope, DISubprogram};
 use common::{CrateContext, FunctionContext};
 use rustc::hir::pat_util;
-use rustc::mir::repr::{Mir, ScopeId};
+use rustc::mir::repr::{Mir, VisibilityScope};
 use rustc::util::nodemap::NodeMap;
 
 use libc::c_uint;
@@ -71,7 +71,7 @@ pub fn create_scope_map(cx: &CrateContext,
 /// If debuginfo is disabled, the returned vector is empty.
 pub fn create_mir_scopes(fcx: &FunctionContext) -> Vec<DIScope> {
     let mir = fcx.mir.clone().expect("create_mir_scopes: missing MIR for fn");
-    let mut scopes = vec![ptr::null_mut(); mir.scopes.len()];
+    let mut scopes = vec![ptr::null_mut(); mir.visibility_scopes.len()];
 
     let fn_metadata = match fcx.debug_context {
         FunctionDebugContext::RegularContext(box ref data) => data.fn_metadata,
@@ -82,14 +82,14 @@ pub fn create_mir_scopes(fcx: &FunctionContext) -> Vec<DIScope> {
     };
 
     // Find all the scopes with variables defined in them.
-    let mut has_variables = BitVector::new(mir.scopes.len());
+    let mut has_variables = BitVector::new(mir.visibility_scopes.len());
     for var in &mir.var_decls {
         has_variables.insert(var.scope.index());
     }
 
     // Instantiate all scopes.
-    for idx in 0..mir.scopes.len() {
-        let scope = ScopeId::new(idx);
+    for idx in 0..mir.visibility_scopes.len() {
+        let scope = VisibilityScope::new(idx);
         make_mir_scope(fcx.ccx, &mir, &has_variables, fn_metadata, scope, &mut scopes);
     }
 
@@ -100,14 +100,14 @@ fn make_mir_scope(ccx: &CrateContext,
                   mir: &Mir,
                   has_variables: &BitVector,
                   fn_metadata: DISubprogram,
-                  scope: ScopeId,
+                  scope: VisibilityScope,
                   scopes: &mut [DIScope]) {
     let idx = scope.index();
     if !scopes[idx].is_null() {
         return;
     }
 
-    let scope_data = &mir.scopes[scope];
+    let scope_data = &mir.visibility_scopes[scope];
     let parent_scope = if let Some(parent) = scope_data.parent_scope {
         make_mir_scope(ccx, mir, has_variables, fn_metadata, parent, scopes);
         scopes[parent.index()]
diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs
index d1206550b13..a6174cd4d37 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -266,16 +266,13 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
     let mut idx = 0;
     let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize;
 
-    // Get the argument scope assuming ScopeId(0) has no parent.
-    let arg_scope = mir.scopes.get(0).and_then(|data| {
-        let scope = scopes[0];
-        if data.parent_scope.is_none() && !scope.is_null() &&
-           bcx.sess().opts.debuginfo == FullDebugInfo {
-            Some(scope)
-        } else {
-            None
-        }
-    });
+    // Get the argument scope, if it exists and if we need it.
+    let arg_scope = scopes[mir::ARGUMENT_VISIBILITY_SCOPE.index()];
+    let arg_scope = if !arg_scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo {
+        Some(arg_scope)
+    } else {
+        None
+    };
 
     mir.arg_decls.iter().enumerate().map(|(arg_index, arg_decl)| {
         let arg_ty = bcx.monomorphize(&arg_decl.ty);
diff --git a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs
index f0ecda92993..b5b6ca75727 100644
--- a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs
+++ b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs
@@ -247,11 +247,10 @@
 // lldb-command:continue
 
 #![allow(dead_code, unused_assignments, unused_variables)]
-#![feature(omit_gdb_pretty_printer_section, rustc_attrs)]
+#![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn immediate_args(a: isize, b: bool, c: f64) {
     println!("");
 }
@@ -268,51 +267,43 @@ struct BigStruct {
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn non_immediate_args(a: BigStruct, b: BigStruct) {
     println!("");
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn binding(a: i64, b: u64, c: f64) {
     let x = 0;
     println!("");
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn assignment(mut a: u64, b: u64, c: f64) {
     a = b;
     println!("");
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn function_call(x: u64, y: u64, z: f64) {
     println!("Hi!")
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn identifier(x: u64, y: u64, z: f64) -> u64 {
     x
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn return_expr(x: u64, y: u64, z: f64) -> u64 {
     return x;
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn arithmetic_expr(x: u64, y: u64, z: f64) -> u64 {
     x + y
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn if_expr(x: u64, y: u64, z: f64) -> u64 {
     if x + y < 1000 {
         x
@@ -322,7 +313,6 @@ fn if_expr(x: u64, y: u64, z: f64) -> u64 {
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn while_expr(mut x: u64, y: u64, z: u64) -> u64 {
     while x + y < 1000 {
         x += z
@@ -331,7 +321,6 @@ fn while_expr(mut x: u64, y: u64, z: u64) -> u64 {
 }
 
 #[no_stack_check]
-#[rustc_no_mir] // FIXME(#32949) MIR debuginfo shadows arguments with uninit vars.
 fn loop_expr(mut x: u64, y: u64, z: u64) -> u64 {
     loop {
         x += z;