diff options
| author | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2017-09-13 22:33:07 +0300 |
|---|---|---|
| committer | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2017-09-24 12:46:00 +0300 |
| commit | 8c7500f9b68d56b8313a8d3c103fd31b638ec8d2 (patch) | |
| tree | 31c91902690085030bc20f6867c261cc9ef20437 | |
| parent | acb73dbe8b311eb2ffa640ac3e01795d84159df4 (diff) | |
| download | rust-8c7500f9b68d56b8313a8d3c103fd31b638ec8d2.tar.gz rust-8c7500f9b68d56b8313a8d3c103fd31b638ec8d2.zip | |
add lint levels to VisibilityScope
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(_))) => { |
