about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-09-13 22:33:07 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2017-09-24 12:46:00 +0300
commit8c7500f9b68d56b8313a8d3c103fd31b638ec8d2 (patch)
tree31c91902690085030bc20f6867c261cc9ef20437
parentacb73dbe8b311eb2ffa640ac3e01795d84159df4 (diff)
downloadrust-8c7500f9b68d56b8313a8d3c103fd31b638ec8d2.tar.gz
rust-8c7500f9b68d56b8313a8d3c103fd31b638ec8d2.zip
add lint levels to VisibilityScope
-rw-r--r--src/librustc/ich/impls_mir.rs18
-rw-r--r--src/librustc/lint/levels.rs5
-rw-r--r--src/librustc/mir/mod.rs45
-rw-r--r--src/librustc/mir/visit.rs2
-rw-r--r--src/librustc_driver/driver.rs7
-rw-r--r--src/librustc_mir/build/block.rs18
-rw-r--r--src/librustc_mir/build/expr/as_constant.rs2
-rw-r--r--src/librustc_mir/build/expr/as_lvalue.rs4
-rw-r--r--src/librustc_mir/build/expr/as_operand.rs4
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs5
-rw-r--r--src/librustc_mir/build/expr/as_temp.rs4
-rw-r--r--src/librustc_mir/build/expr/into.rs5
-rw-r--r--src/librustc_mir/build/expr/stmt.rs4
-rw-r--r--src/librustc_mir/build/matches/mod.rs21
-rw-r--r--src/librustc_mir/build/mod.rs26
-rw-r--r--src/librustc_mir/build/scope.rs38
-rw-r--r--src/librustc_mir/hair/cx/block.rs1
-rw-r--r--src/librustc_mir/hair/cx/expr.rs26
-rw-r--r--src/librustc_mir/hair/cx/mod.rs48
-rw-r--r--src/librustc_mir/hair/mod.rs22
-rw-r--r--src/librustc_mir/shim.rs5
-rw-r--r--src/librustc_mir/transform/generator.rs3
-rw-r--r--src/librustc_mir/transform/promote_consts.rs8
-rw-r--r--src/librustc_typeck/check/mod.rs1
24 files changed, 269 insertions, 53 deletions
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index 9b6613e4cae..068830d688c 100644
--- a/src/librustc/ich/impls_mir.rs
+++ b/src/librustc/ich/impls_mir.rs
@@ -28,6 +28,7 @@ impl_stable_hash_for!(struct mir::LocalDecl<'tcx> {
     name,
     source_info,
     internal,
+    lexical_scope,
     is_user_variable
 });
 impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref });
@@ -75,6 +76,22 @@ for mir::Terminator<'gcx> {
     }
 }
 
+impl<'gcx, T> HashStable<StableHashingContext<'gcx>> for mir::ClearOnDecode<T>
+    where T: HashStable<StableHashingContext<'gcx>>
+{
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            mir::ClearOnDecode::Clear => {}
+            mir::ClearOnDecode::Set(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
 
 impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Local {
     #[inline]
@@ -347,6 +364,7 @@ for mir::ProjectionElem<'gcx, V, T>
 }
 
 impl_stable_hash_for!(struct mir::VisibilityScopeData { span, parent_scope });
+impl_stable_hash_for!(struct mir::VisibilityScopeInfo { lint_root });
 
 impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Operand<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs
index 21dfd3267df..4bc37747f2a 100644
--- a/src/librustc/lint/levels.rs
+++ b/src/librustc/lint/levels.rs
@@ -384,6 +384,11 @@ impl LintLevelMap {
             self.sets.get_lint_level(lint, *idx, None)
         })
     }
+
+    /// Returns if this `id` has lint level information.
+    pub fn lint_level_set(&self, id: HirId) -> Option<u32> {
+        self.id_to_set.get(&id).cloned()
+    }
 }
 
 impl<'gcx> HashStable<StableHashingContext<'gcx>> for LintLevelMap {
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index d43504b77ba..09da1d1f820 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -18,6 +18,7 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators};
 use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccessors};
 use rustc_data_structures::control_flow_graph::ControlFlowGraph;
+use rustc_serialize as serialize;
 use hir::def::CtorKind;
 use hir::def_id::DefId;
 use ty::subst::{Subst, Substs};
@@ -33,7 +34,7 @@ use std::fmt::{self, Debug, Formatter, Write};
 use std::{iter, u32};
 use std::ops::{Index, IndexMut};
 use std::vec::IntoIter;
-use syntax::ast::Name;
+use syntax::ast::{self, Name};
 use syntax_pos::Span;
 
 mod cache;
@@ -96,6 +97,10 @@ pub struct Mir<'tcx> {
     /// and used (eventually) for debuginfo. Indexed by a `VisibilityScope`.
     pub visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
 
+    /// Crate-local information for each visibility scope, that can't (and
+    /// needn't) be tracked across crates.
+    pub visibility_scope_info: ClearOnDecode<IndexVec<VisibilityScope, VisibilityScopeInfo>>,
+
     /// 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
     /// in scope, but a separate set of locals.
@@ -151,6 +156,8 @@ pub const START_BLOCK: BasicBlock = BasicBlock(0);
 impl<'tcx> Mir<'tcx> {
     pub fn new(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
                visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
+               visibility_scope_info: ClearOnDecode<IndexVec<VisibilityScope,
+                                                             VisibilityScopeInfo>>,
                promoted: IndexVec<Promoted, Mir<'tcx>>,
                return_ty: Ty<'tcx>,
                yield_ty: Option<Ty<'tcx>>,
@@ -167,6 +174,7 @@ impl<'tcx> Mir<'tcx> {
         Mir {
             basic_blocks,
             visibility_scopes,
+            visibility_scope_info,
             promoted,
             return_ty,
             yield_ty,
@@ -278,9 +286,16 @@ impl<'tcx> Mir<'tcx> {
     }
 }
 
+#[derive(Clone, Debug)]
+pub struct VisibilityScopeInfo {
+    /// A NodeId with lint levels equivalent to this scope's lint levels.
+    pub lint_root: ast::NodeId,
+}
+
 impl_stable_hash_for!(struct Mir<'tcx> {
     basic_blocks,
     visibility_scopes,
+    visibility_scope_info,
     promoted,
     return_ty,
     yield_ty,
@@ -310,6 +325,24 @@ impl<'tcx> IndexMut<BasicBlock> for Mir<'tcx> {
     }
 }
 
+#[derive(Clone, Debug)]
+pub enum ClearOnDecode<T> {
+    Clear,
+    Set(T)
+}
+
+impl<T> serialize::Encodable for ClearOnDecode<T> {
+    fn encode<S: serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        serialize::Encodable::encode(&(), s)
+    }
+}
+
+impl<T> serialize::Decodable for ClearOnDecode<T> {
+    fn decode<D: serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
+        serialize::Decodable::decode(d).map(|()| ClearOnDecode::Clear)
+    }
+}
+
 /// Grouped information about the source code origin of a MIR entity.
 /// Intended to be inspected by diagnostics and debuginfo.
 /// Most passes can work with it as a whole, within a single function.
@@ -438,6 +471,12 @@ pub struct LocalDecl<'tcx> {
 
     /// Source info of the local.
     pub source_info: SourceInfo,
+
+    /// The *lexical* visibility scope the local is defined
+    /// in. If the local was defined in a let-statement, this
+    /// is *within* the let-statement, rather than outside
+    /// of iit.
+    pub lexical_scope: VisibilityScope,
 }
 
 impl<'tcx> LocalDecl<'tcx> {
@@ -452,6 +491,7 @@ impl<'tcx> LocalDecl<'tcx> {
                 span,
                 scope: ARGUMENT_VISIBILITY_SCOPE
             },
+            lexical_scope: ARGUMENT_VISIBILITY_SCOPE,
             internal: false,
             is_user_variable: false
         }
@@ -468,6 +508,7 @@ impl<'tcx> LocalDecl<'tcx> {
                 span,
                 scope: ARGUMENT_VISIBILITY_SCOPE
             },
+            lexical_scope: ARGUMENT_VISIBILITY_SCOPE,
             internal: true,
             is_user_variable: false
         }
@@ -485,6 +526,7 @@ impl<'tcx> LocalDecl<'tcx> {
                 span,
                 scope: ARGUMENT_VISIBILITY_SCOPE
             },
+            lexical_scope: ARGUMENT_VISIBILITY_SCOPE,
             internal: false,
             name: None,     // FIXME maybe we do want some name here?
             is_user_variable: false
@@ -1607,6 +1649,7 @@ impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> {
         Mir {
             basic_blocks: self.basic_blocks.fold_with(folder),
             visibility_scopes: self.visibility_scopes.clone(),
+            visibility_scope_info: self.visibility_scope_info.clone(),
             promoted: self.promoted.fold_with(folder),
             return_ty: self.return_ty.fold_with(folder),
             yield_ty: self.yield_ty.fold_with(folder),
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 37c97ad3dad..63652980f9b 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -690,11 +690,13 @@ macro_rules! make_mir_visitor {
                     name: _,
                     ref $($mutability)* source_info,
                     internal: _,
+                    ref $($mutability)* lexical_scope,
                     is_user_variable: _,
                 } = *local_decl;
 
                 self.visit_ty(ty, Lookup::Src(*source_info));
                 self.visit_source_info(source_info);
+                self.visit_visibility_scope(lexical_scope);
             }
 
             fn super_visibility_scope(&mut self,
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index bcfbc1980cf..5116a3087d2 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -1009,15 +1009,16 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
     // FIXME: ariel points SimplifyBranches should run after
     // mir-borrowck; otherwise code within `if false { ... }` would
     // not be checked.
-    passes.push_pass(MIR_VALIDATED,
-                     mir::transform::simplify_branches::SimplifyBranches::new("initial"));
     passes.push_pass(MIR_VALIDATED, mir::transform::simplify::SimplifyCfg::new("qualify-consts"));
     passes.push_pass(MIR_VALIDATED, mir::transform::nll::NLL);
 
     // borrowck runs between MIR_VALIDATED and MIR_OPTIMIZED.
 
-    // These next passes must be executed together
     passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
+    passes.push_pass(MIR_OPTIMIZED,
+                     mir::transform::simplify_branches::SimplifyBranches::new("initial"));
+
+    // These next passes must be executed together
     passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::CriticalCallEdges);
     passes.push_pass(MIR_OPTIMIZED, mir::transform::elaborate_drops::ElaborateDrops);
     passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index 0e412fb27ca..db04596dd58 100644
--- a/src/librustc_mir/build/block.rs
+++ b/src/librustc_mir/build/block.rs
@@ -24,7 +24,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let Block { region_scope, opt_destruction_scope, span, stmts, expr, targeted_by_break } =
             self.hir.mirror(ast_block);
         self.in_opt_scope(opt_destruction_scope.map(|de|(de, source_info)), block, move |this| {
-            this.in_scope((region_scope, source_info), block, move |this| {
+            this.in_scope((region_scope, source_info), LintLevel::Inherited, block, move |this| {
                 if targeted_by_break {
                     // This is a `break`-able block (currently only `catch { ... }`)
                     let exit_block = this.cfg.start_new_block();
@@ -76,13 +76,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 StmtKind::Expr { scope, expr } => {
                     unpack!(block = this.in_opt_scope(
                         opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
-                            this.in_scope((scope, source_info), block, |this| {
+                            let si = (scope, source_info);
+                            this.in_scope(si, LintLevel::Inherited, block, |this| {
                                 let expr = this.hir.mirror(expr);
                                 this.stmt_expr(block, expr)
                             })
                         }));
                 }
-                StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => {
+                StmtKind::Let {
+                    remainder_scope,
+                    init_scope,
+                    pattern,
+                    initializer,
+                    lint_level
+                } => {
                     // Enter the remainder scope, i.e. the bindings' destruction scope.
                     this.push_scope((remainder_scope, source_info));
                     let_scope_stack.push(remainder_scope);
@@ -90,13 +97,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     // Declare the bindings, which may create a visibility scope.
                     let remainder_span = remainder_scope.span(this.hir.tcx(),
                                                               &this.hir.region_scope_tree);
-                    let scope = this.declare_bindings(None, remainder_span, &pattern);
+                    let scope = this.declare_bindings(None, remainder_span, lint_level, &pattern);
 
                     // Evaluate the initializer, if present.
                     if let Some(init) = initializer {
                         unpack!(block = this.in_opt_scope(
                             opt_destruction_scope.map(|de|(de, source_info)), block, move |this| {
-                                this.in_scope((init_scope, source_info), block, move |this| {
+                                let scope = (init_scope, source_info);
+                                this.in_scope(scope, lint_level, block, move |this| {
                                     // FIXME #30046                             ^~~~
                                     this.expr_into_pattern(block, pattern, init)
                                 })
diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs
index a86b7f4d239..a57f1b95494 100644
--- a/src/librustc_mir/build/expr/as_constant.rs
+++ b/src/librustc_mir/build/expr/as_constant.rs
@@ -29,7 +29,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let Expr { ty, temp_lifetime: _, span, kind }
             = expr;
         match kind {
-            ExprKind::Scope { region_scope: _, value } =>
+            ExprKind::Scope { region_scope: _, lint_level: _, value } =>
                 this.as_constant(value),
             ExprKind::Literal { literal } =>
                 Constant { span: span, ty: ty, literal: literal },
diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs
index 9cbaff2c113..69d0dd99228 100644
--- a/src/librustc_mir/build/expr/as_lvalue.rs
+++ b/src/librustc_mir/build/expr/as_lvalue.rs
@@ -39,8 +39,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let expr_span = expr.span;
         let source_info = this.source_info(expr_span);
         match expr.kind {
-            ExprKind::Scope { region_scope, value } => {
-                this.in_scope((region_scope, source_info), block, |this| {
+            ExprKind::Scope { region_scope, lint_level, value } => {
+                this.in_scope((region_scope, source_info), lint_level, block, |this| {
                     this.as_lvalue(block, value)
                 })
             }
diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs
index 0a72ce8d05e..ea6e4342098 100644
--- a/src/librustc_mir/build/expr/as_operand.rs
+++ b/src/librustc_mir/build/expr/as_operand.rs
@@ -55,10 +55,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         debug!("expr_as_operand(block={:?}, expr={:?})", block, expr);
         let this = self;
 
-        if let ExprKind::Scope { region_scope, value } = expr.kind {
+        if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
             let source_info = this.source_info(expr.span);
             let region_scope = (region_scope, source_info);
-            return this.in_scope(region_scope, block, |this| {
+            return this.in_scope(region_scope, lint_level, block, |this| {
                 this.as_operand(block, scope, value)
             });
         }
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index f2607b164de..d17f00b489c 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -58,9 +58,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let source_info = this.source_info(expr_span);
 
         match expr.kind {
-            ExprKind::Scope { region_scope, value } => {
+            ExprKind::Scope { region_scope, lint_level, value } => {
                 let region_scope = (region_scope, source_info);
-                this.in_scope(region_scope, block, |this| this.as_rvalue(block, scope, value))
+                this.in_scope(region_scope, lint_level, block,
+                              |this| this.as_rvalue(block, scope, value))
             }
             ExprKind::Repeat { value, count } => {
                 let value_operand = unpack!(block = this.as_operand(block, scope, value));
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index 7826769600b..ba422a81831 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -41,8 +41,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         let expr_span = expr.span;
         let source_info = this.source_info(expr_span);
-        if let ExprKind::Scope { region_scope, value } = expr.kind {
-            return this.in_scope((region_scope, source_info), block, |this| {
+        if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
+            return this.in_scope((region_scope, source_info), lint_level, block, |this| {
                 this.as_temp(block, temp_lifetime, value)
             });
         }
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index ec06e474980..65e16657a03 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -38,9 +38,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let source_info = this.source_info(expr_span);
 
         match expr.kind {
-            ExprKind::Scope { region_scope, value } => {
+            ExprKind::Scope { region_scope, lint_level, value } => {
                 let region_scope = (region_scope, source_info);
-                this.in_scope(region_scope, block, |this| this.into(destination, block, value))
+                this.in_scope(region_scope, lint_level, block,
+                              |this| this.into(destination, block, value))
             }
             ExprKind::Block { body: ast_block } => {
                 this.ast_block(destination, block, ast_block, source_info)
diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs
index 84468d5d6dc..3cfb0ff4010 100644
--- a/src/librustc_mir/build/expr/stmt.rs
+++ b/src/librustc_mir/build/expr/stmt.rs
@@ -22,9 +22,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         // Handle a number of expressions that don't need a destination at all. This
         // avoids needing a mountain of temporary `()` variables.
         match expr.kind {
-            ExprKind::Scope { region_scope, value } => {
+            ExprKind::Scope { region_scope, lint_level, value } => {
                 let value = this.hir.mirror(value);
-                this.in_scope((region_scope, source_info), block, |this| {
+                this.in_scope((region_scope, source_info), lint_level, block, |this| {
                     this.stmt_expr(block, value)
                 })
             }
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index f560fa426e2..b856e6345dc 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -46,8 +46,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         // Get the arm bodies and their scopes, while declaring bindings.
         let arm_bodies: Vec<_> = arms.iter().map(|arm| {
+            // BUG: use arm lint level
             let body = self.hir.mirror(arm.body.clone());
-            let scope = self.declare_bindings(None, body.span, &arm.patterns[0]);
+            let scope = self.declare_bindings(None, body.span,
+                                              LintLevel::Inherited,
+                                              &arm.patterns[0]);
             (body, scope.unwrap_or(self.visibility_scope))
         }).collect();
 
@@ -171,11 +174,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn declare_bindings(&mut self,
                             mut var_scope: Option<VisibilityScope>,
                             scope_span: Span,
+                            lint_level: LintLevel,
                             pattern: &Pattern<'tcx>)
                             -> Option<VisibilityScope> {
+        assert!(!(var_scope.is_some() && lint_level.is_explicit()),
+               "can't have both a var and a lint scope at the same time");
         self.visit_bindings(pattern, &mut |this, mutability, name, var, span, ty| {
             if var_scope.is_none() {
-                var_scope = Some(this.new_visibility_scope(scope_span));
+                var_scope = Some(this.new_visibility_scope(scope_span,
+                                                           LintLevel::Inherited));
+                // If we have lints, create a new visibility scope
+                // that marks the lints for the locals.
+                if lint_level.is_explicit() {
+                    this.new_visibility_scope(scope_span, lint_level);
+                }
             }
             let source_info = SourceInfo {
                 span,
@@ -183,6 +195,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             };
             this.declare_binding(source_info, mutability, name, var, ty);
         });
+        // Pop any scope we created for the locals.
+        if let Some(var_scope) = var_scope {
+            self.visibility_scope = var_scope;
+        }
         var_scope
     }
 
@@ -712,6 +728,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             ty: var_ty.clone(),
             name: Some(name),
             source_info,
+            lexical_scope: self.visibility_scope,
             internal: false,
             is_user_variable: true,
         });
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index be6f8c9e56c..9c2c5bbcdb8 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -11,6 +11,7 @@
 
 use build;
 use hair::cx::Cx;
+use hair::LintLevel;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::middle::region;
@@ -277,6 +278,7 @@ 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
     visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
+    visibility_scope_info: IndexVec<VisibilityScope, VisibilityScopeInfo>,
     visibility_scope: VisibilityScope,
 
     /// Maps node ids of variable bindings to the `Local`s created for them.
@@ -378,8 +380,10 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
     let arg_scope = region::Scope::Arguments(body.value.hir_id.local_id);
     let mut block = START_BLOCK;
     let source_info = builder.source_info(span);
-    unpack!(block = builder.in_scope((call_site_scope, source_info), block, |builder| {
-        unpack!(block = builder.in_scope((arg_scope, source_info), block, |builder| {
+    let call_site_s = (call_site_scope, source_info);
+    unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, block, |builder| {
+        let arg_scope_s = (arg_scope, source_info);
+        unpack!(block = builder.in_scope(arg_scope_s, LintLevel::Inherited, block, |builder| {
             builder.args_and_body(block, &arguments, arg_scope, &body.value)
         }));
         // Attribute epilogue to function's closing brace
@@ -456,9 +460,10 @@ fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
 }
 
 fn construct_error<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
-                                       body_id: hir::BodyId)
-                                       -> Mir<'tcx> {
-    let span = hir.tcx().hir.span(hir.tcx().hir.body_owner(body_id));
+                                   body_id: hir::BodyId)
+                                   -> Mir<'tcx> {
+    let owner_id = hir.tcx().hir.body_owner(body_id);
+    let span = hir.tcx().hir.span(owner_id);
     let ty = hir.tcx().types.err;
     let mut builder = Builder::new(hir, span, 0, ty);
     let source_info = builder.source_info(span);
@@ -472,6 +477,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
            arg_count: usize,
            return_ty: Ty<'tcx>)
            -> Builder<'a, 'gcx, 'tcx> {
+        let lint_level = LintLevel::Explicit(hir.root_lint_level);
         let mut builder = Builder {
             hir,
             cfg: CFG { basic_blocks: IndexVec::new() },
@@ -480,6 +486,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             scopes: vec![],
             visibility_scopes: IndexVec::new(),
             visibility_scope: ARGUMENT_VISIBILITY_SCOPE,
+            visibility_scope_info: IndexVec::new(),
             breakable_scopes: vec![],
             local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty,
                                                                              span), 1),
@@ -490,7 +497,9 @@ 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);
+        assert_eq!(
+            builder.new_visibility_scope(span, lint_level),
+            ARGUMENT_VISIBILITY_SCOPE);
         builder.visibility_scopes[ARGUMENT_VISIBILITY_SCOPE].parent_scope = None;
 
         builder
@@ -509,6 +518,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         Mir::new(self.cfg.basic_blocks,
                  self.visibility_scopes,
+                 ClearOnDecode::Set(self.visibility_scope_info),
                  IndexVec::new(),
                  return_ty,
                  yield_ty,
@@ -543,6 +553,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     scope: ARGUMENT_VISIBILITY_SCOPE,
                     span: pattern.map_or(self.fn_span, |pat| pat.span)
                 },
+                lexical_scope: ARGUMENT_VISIBILITY_SCOPE,
                 name,
                 internal: false,
                 is_user_variable: false,
@@ -557,7 +568,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
             if let Some(pattern) = pattern {
                 let pattern = self.hir.pattern_from_hir(pattern);
-                scope = self.declare_bindings(scope, ast_body.span, &pattern);
+                scope = self.declare_bindings(scope, ast_body.span,
+                                              LintLevel::Inherited, &pattern);
                 unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue));
             }
 
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index bac884b4d01..62613c7168a 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -88,8 +88,10 @@ should go to.
 */
 
 use build::{BlockAnd, BlockAndExtension, Builder, CFG};
+use hair::LintLevel;
 use rustc::middle::region;
 use rustc::ty::{Ty, TyCtxt};
+use rustc::hir::def_id::LOCAL_CRATE;
 use rustc::mir::*;
 use rustc::mir::transform::MirSource;
 use syntax_pos::{Span};
@@ -304,15 +306,37 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// to build its contents, popping the scope afterwards.
     pub fn in_scope<F, R>(&mut self,
                           region_scope: (region::Scope, SourceInfo),
+                          lint_level: LintLevel,
                           mut block: BasicBlock,
                           f: F)
                           -> BlockAnd<R>
         where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd<R>
     {
         debug!("in_scope(region_scope={:?}, block={:?})", region_scope, block);
+        let visibility_scope = self.visibility_scope;
+        let tcx = self.hir.tcx();
+        if let LintLevel::Explicit(node_id) = lint_level {
+            let same_lint_scopes = tcx.dep_graph.with_ignore(|| {
+                let sets = tcx.lint_levels(LOCAL_CRATE);
+                let parent_hir_id =
+                    tcx.hir.definitions().node_to_hir_id(
+                        self.visibility_scope_info[visibility_scope].lint_root
+                            );
+                let current_hir_id =
+                    tcx.hir.definitions().node_to_hir_id(node_id);
+                sets.lint_level_set(parent_hir_id) ==
+                    sets.lint_level_set(current_hir_id)
+            });
+
+            if !same_lint_scopes {
+                self.visibility_scope =
+                    self.new_visibility_scope(region_scope.1.span, lint_level);
+            }
+        }
         self.push_scope(region_scope);
         let rv = unpack!(block = f(self));
         unpack!(block = self.pop_scope(region_scope, block));
+        self.visibility_scope = visibility_scope;
         debug!("in_scope: exiting region_scope={:?} block={:?}", region_scope, block);
         block.and(rv)
     }
@@ -474,13 +498,21 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     }
 
     /// Creates a new visibility scope, nested in the current one.
-    pub fn new_visibility_scope(&mut self, span: Span) -> VisibilityScope {
+    pub fn new_visibility_scope(&mut self,
+                                span: Span,
+                                lint_level: LintLevel) -> VisibilityScope {
+        debug!("new_visibility_scope({:?}, {:?})", span, lint_level);
         let parent = self.visibility_scope;
-        let scope = VisibilityScope::new(self.visibility_scopes.len());
-        self.visibility_scopes.push(VisibilityScopeData {
+        let info = if let LintLevel::Explicit(lint_level) = lint_level {
+            VisibilityScopeInfo { lint_root: lint_level }
+        } else {
+            self.visibility_scope_info[parent].clone()
+        };
+        let scope = self.visibility_scopes.push(VisibilityScopeData {
             span,
             parent_scope: Some(parent),
         });
+        self.visibility_scope_info.push(info);
         scope
     }
 
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index f6b847d6d6d..1c1fc2dcafa 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -71,6 +71,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                 init_scope: region::Scope::Node(hir_id.local_id),
                                 pattern,
                                 initializer: local.init.to_ref(),
+                                lint_level: cx.lint_level_of(local.id),
                             },
                             opt_destruction_scope: opt_dxn_ext,
                         })));
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 45449103c80..f5a53e2aa8e 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -48,22 +48,24 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
             kind: ExprKind::Scope {
                 region_scope: expr_scope,
                 value: expr.to_ref(),
+                lint_level: cx.lint_level_of(self.id),
             },
         };
 
         // Finally, create a destruction scope, if any.
         if let Some(region_scope) =
-                cx.region_scope_tree.opt_destruction_scope(self.hir_id.local_id) {
-            expr = Expr {
-                temp_lifetime,
-                ty: expr.ty,
-                span: self.span,
-                kind: ExprKind::Scope {
-                    region_scope,
-                    value: expr.to_ref(),
-                },
-            };
-        }
+            cx.region_scope_tree.opt_destruction_scope(self.hir_id.local_id) {
+                expr = Expr {
+                    temp_lifetime,
+                    ty: expr.ty,
+                    span: self.span,
+                    kind: ExprKind::Scope {
+                        region_scope,
+                        value: expr.to_ref(),
+                        lint_level: LintLevel::Inherited,
+                    },
+                };
+            }
 
         // OK, all done!
         expr
@@ -619,6 +621,8 @@ fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm)
         patterns: arm.pats.iter().map(|p| cx.pattern_from_hir(p)).collect(),
         guard: arm.guard.to_ref(),
         body: arm.body.to_ref(),
+        // BUG: fix this
+        lint_level: LintLevel::Inherited,
     }
 }
 
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index f5e15979006..4434df0ac3e 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -20,13 +20,14 @@ use rustc::mir::transform::MirSource;
 use rustc::middle::const_val::{ConstEvalErr, ConstVal};
 use rustc_const_eval::ConstContext;
 use rustc_data_structures::indexed_vec::Idx;
-use rustc::hir::def_id::DefId;
+use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::middle::region;
 use rustc::infer::InferCtxt;
 use rustc::ty::subst::Subst;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::Substs;
+use syntax::ast;
 use syntax::symbol::Symbol;
 use rustc::hir;
 use rustc_const_math::{ConstInt, ConstUsize};
@@ -37,6 +38,7 @@ pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
 
+    pub root_lint_level: ast::NodeId,
     pub param_env: ty::ParamEnv<'gcx>,
 
     /// Identity `Substs` for use with const-evaluation.
@@ -57,7 +59,8 @@ pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
 }
 
 impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
-    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, src: MirSource) -> Cx<'a, 'gcx, 'tcx> {
+    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+               src: MirSource) -> Cx<'a, 'gcx, 'tcx> {
         let constness = match src {
             MirSource::Const(_) |
             MirSource::Static(..) => hir::Constness::Const,
@@ -87,9 +90,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         // Constants and const fn's always need overflow checks.
         check_overflow |= constness == hir::Constness::Const;
 
+        let lint_level = lint_level_for_hir_id(tcx, src_id);
         Cx {
             tcx,
             infcx,
+            root_lint_level: lint_level,
             param_env: tcx.param_env(src_def_id),
             identity_substs: Substs::identity_for_item(tcx.global_tcx(), src_def_id),
             region_scope_tree: tcx.region_scope_tree(src_def_id),
@@ -99,6 +104,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
             check_overflow,
         }
     }
+
 }
 
 impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
@@ -229,6 +235,19 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         ty.needs_drop(self.tcx.global_tcx(), param_env)
     }
 
+    fn lint_level_of(&self, node_id: ast::NodeId) -> LintLevel {
+        let hir_id = self.tcx.hir.definitions().node_to_hir_id(node_id);
+        let has_lint_level = self.tcx.dep_graph.with_ignore(|| {
+            self.tcx.lint_levels(LOCAL_CRATE).lint_level_set(hir_id).is_some()
+        });
+
+        if has_lint_level {
+            LintLevel::Explicit(node_id)
+        } else {
+            LintLevel::Inherited
+        }
+    }
+
     pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
         self.tcx
     }
@@ -242,6 +261,31 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
     }
 }
 
+fn lint_level_for_hir_id(tcx: TyCtxt, mut id: ast::NodeId) -> ast::NodeId {
+    // Right now we insert a `with_ignore` node in the dep graph here to
+    // ignore the fact that `lint_levels` below depends on the entire crate.
+    // For now this'll prevent false positives of recompiling too much when
+    // anything changes.
+    //
+    // Once red/green incremental compilation lands we should be able to
+    // remove this because while the crate changes often the lint level map
+    // will change rarely.
+    tcx.dep_graph.with_ignore(|| {
+        let sets = tcx.lint_levels(LOCAL_CRATE);
+        loop {
+            let hir_id = tcx.hir.definitions().node_to_hir_id(id);
+            if sets.lint_level_set(hir_id).is_some() {
+                return id
+            }
+            let next = tcx.hir.get_parent_node(id);
+            if next == id {
+                bug!("lint traversal reached the root of the crate");
+            }
+            id = next;
+        }
+    })
+}
+
 mod block;
 mod expr;
 mod to_ref;
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 3162242de66..0c8dba5159f 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -29,6 +29,21 @@ pub mod cx;
 
 pub use rustc_const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
 
+#[derive(Copy, Clone, Debug)]
+pub enum LintLevel {
+    Inherited,
+    Explicit(ast::NodeId)
+}
+
+impl LintLevel {
+    pub fn is_explicit(self) -> bool {
+        match self {
+            LintLevel::Inherited => false,
+            LintLevel::Explicit(_) => true
+        }
+    }
+}
+
 #[derive(Clone, Debug)]
 pub struct Block<'tcx> {
     pub targeted_by_break: bool,
@@ -73,7 +88,10 @@ pub enum StmtKind<'tcx> {
         pattern: Pattern<'tcx>,
 
         /// let pat = <INIT> ...
-        initializer: Option<ExprRef<'tcx>>
+        initializer: Option<ExprRef<'tcx>>,
+
+        /// the lint level for this let-statement
+        lint_level: LintLevel,
     },
 }
 
@@ -111,6 +129,7 @@ pub struct Expr<'tcx> {
 pub enum ExprKind<'tcx> {
     Scope {
         region_scope: region::Scope,
+        lint_level: LintLevel,
         value: ExprRef<'tcx>,
     },
     Box {
@@ -275,6 +294,7 @@ pub struct Arm<'tcx> {
     pub patterns: Vec<Pattern<'tcx>>,
     pub guard: Option<ExprRef<'tcx>>,
     pub body: ExprRef<'tcx>,
+    pub lint_level: LintLevel,
 }
 
 #[derive(Copy, Clone, Debug)]
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 31480457723..a3a986918a4 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -140,6 +140,7 @@ fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl {
     LocalDecl {
         mutability, ty, name: None,
         source_info: SourceInfo { scope: ARGUMENT_VISIBILITY_SCOPE, span },
+        lexical_scope: ARGUMENT_VISIBILITY_SCOPE,
         internal: false,
         is_user_variable: false
     }
@@ -195,6 +196,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         IndexVec::from_elem_n(
             VisibilityScopeData { span: span, parent_scope: None }, 1
         ),
+        ClearOnDecode::Clear,
         IndexVec::new(),
         sig.output(),
         None,
@@ -342,6 +344,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
             IndexVec::from_elem_n(
                 VisibilityScopeData { span: self.span, parent_scope: None }, 1
             ),
+            ClearOnDecode::Clear,
             IndexVec::new(),
             self.sig.output(),
             None,
@@ -804,6 +807,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         IndexVec::from_elem_n(
             VisibilityScopeData { span: span, parent_scope: None }, 1
         ),
+        ClearOnDecode::Clear,
         IndexVec::new(),
         sig.output(),
         None,
@@ -876,6 +880,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
         IndexVec::from_elem_n(
             VisibilityScopeData { span: span, parent_scope: None }, 1
         ),
+        ClearOnDecode::Clear,
         IndexVec::new(),
         sig.output(),
         None,
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index 507a42970c1..729fe46ef37 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -301,6 +301,7 @@ fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>,
         ty: ret_ty,
         name: None,
         source_info: source_info(mir),
+        lexical_scope: ARGUMENT_VISIBILITY_SCOPE,
         internal: false,
         is_user_variable: false,
     };
@@ -559,6 +560,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
         ty: tcx.mk_nil(),
         name: None,
         source_info,
+        lexical_scope: ARGUMENT_VISIBILITY_SCOPE,
         internal: false,
         is_user_variable: false,
     };
@@ -574,6 +576,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
         }),
         name: None,
         source_info,
+        lexical_scope: ARGUMENT_VISIBILITY_SCOPE,
         internal: false,
         is_user_variable: false,
     };
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index ca6eda5c2d7..339ea8a414b 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -380,10 +380,10 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
         let mut promoter = Promoter {
             promoted: Mir::new(
                 IndexVec::new(),
-                Some(VisibilityScopeData {
-                    span,
-                    parent_scope: None
-                }).into_iter().collect(),
+                // FIXME: maybe try to filter this to avoid blowing up
+                // memory usage?
+                mir.visibility_scopes.clone(),
+                mir.visibility_scope_info.clone(),
                 IndexVec::new(),
                 ty,
                 None,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index edbdfc1a7d4..c6461217ac3 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2236,7 +2236,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                adjusted_ty,
                index_ty);
 
-
         // First, try built-in indexing.
         match (adjusted_ty.builtin_index(), &index_ty.sty) {
             (Some(ty), &ty::TyUint(ast::UintTy::Us)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => {