add lint levels to VisibilityScope

This commit is contained in:
Ariel Ben-Yehuda 2017-09-13 22:33:07 +03:00
parent acb73dbe8b
commit 8c7500f9b6
24 changed files with 269 additions and 53 deletions

View File

@ -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,

View File

@ -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 {

View File

@ -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),

View File

@ -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,

View File

@ -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);

View File

@ -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)
})

View File

@ -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 },

View File

@ -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)
})
}

View File

@ -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)
});
}

View File

@ -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));

View File

@ -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)
});
}

View File

@ -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)

View File

@ -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)
})
}

View File

@ -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,
});

View File

@ -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));
}

View File

@ -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
}

View File

@ -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,
})));

View File

@ -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,
}
}

View File

@ -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;

View File

@ -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)]

View File

@ -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,

View File

@ -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,
};

View File

@ -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,

View File

@ -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(_))) => {