use log::debug;
use std::any::Any;
+use std::cell::Cell;
use std::slice;
/// Extract the `LintStore` from the query context.
$cx.pass.$f(&$cx.context, $($args),*);
}) }
-struct LateContextAndPass<'a, 'tcx, T: LateLintPass<'a, 'tcx>> {
- context: LateContext<'a, 'tcx>,
+struct LateContextAndPass<'tcx, T: LateLintPass<'tcx>> {
+ context: LateContext<'tcx>,
pass: T,
}
-impl<'a, 'tcx, T: LateLintPass<'a, 'tcx>> LateContextAndPass<'a, 'tcx, T> {
+impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> {
/// Merge the lints specified by any lint attributes into the
/// current lint context, call the provided function, then reset the
/// lints in effect to their previous state.
}
}
-impl<'a, 'tcx, T: LateLintPass<'a, 'tcx>> hir_visit::Visitor<'tcx>
- for LateContextAndPass<'a, 'tcx, T>
-{
+impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPass<'tcx, T> {
type Map = Map<'tcx>;
/// Because lints are scoped lexically, we want to walk nested
hir_visit::NestedVisitorMap::All(self.context.tcx.hir())
}
- fn visit_nested_body(&mut self, body: hir::BodyId) {
- let old_tables = self.context.tables;
- self.context.tables = self.context.tcx.body_tables(body);
- let body = self.context.tcx.hir().body(body);
+ fn visit_nested_body(&mut self, body_id: hir::BodyId) {
+ let old_enclosing_body = self.context.enclosing_body.replace(body_id);
+ let old_cached_typeck_tables = self.context.cached_typeck_tables.get();
+
+ // HACK(eddyb) avoid trashing `cached_typeck_tables` when we're
+ // nested in `visit_fn`, which may have already resulted in them
+ // being queried.
+ if old_enclosing_body != Some(body_id) {
+ self.context.cached_typeck_tables.set(None);
+ }
+
+ let body = self.context.tcx.hir().body(body_id);
self.visit_body(body);
- self.context.tables = old_tables;
+ self.context.enclosing_body = old_enclosing_body;
+
+ // See HACK comment above.
+ if old_enclosing_body != Some(body_id) {
+ self.context.cached_typeck_tables.set(old_cached_typeck_tables);
+ }
}
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
) {
// Wrap in tables here, not just in visit_nested_body,
// in order for `check_fn` to be able to use them.
- let old_tables = self.context.tables;
- self.context.tables = self.context.tcx.body_tables(body_id);
+ let old_enclosing_body = self.context.enclosing_body.replace(body_id);
+ let old_cached_typeck_tables = self.context.cached_typeck_tables.take();
let body = self.context.tcx.hir().body(body_id);
lint_callback!(self, check_fn, fk, decl, body, span, id);
hir_visit::walk_fn(self, fk, decl, body_id, span, id);
lint_callback!(self, check_fn_post, fk, decl, body, span, id);
- self.context.tables = old_tables;
+ self.context.enclosing_body = old_enclosing_body;
+ self.context.cached_typeck_tables.set(old_cached_typeck_tables);
}
fn visit_variant_data(
}
macro_rules! expand_late_lint_pass_impl_methods {
- ([$a:tt, $hir:tt], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
- $(fn $name(&mut self, context: &LateContext<$a, $hir>, $($param: $arg),*) {
+ ([$hir:tt], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
+ $(fn $name(&mut self, context: &LateContext<$hir>, $($param: $arg),*) {
for obj in self.lints.iter_mut() {
obj.$name(context, $($param),*);
}
}
macro_rules! late_lint_pass_impl {
- ([], [$hir:tt], $methods:tt) => (
- impl<'a, $hir> LateLintPass<'a, $hir> for LateLintPassObjects<'_> {
- expand_late_lint_pass_impl_methods!(['a, $hir], $methods);
+ ([], [$hir:tt], $methods:tt) => {
+ impl<$hir> LateLintPass<$hir> for LateLintPassObjects<'_> {
+ expand_late_lint_pass_impl_methods!([$hir], $methods);
}
- )
+ };
}
crate::late_lint_methods!(late_lint_pass_impl, [], ['tcx]);
-fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
+fn late_lint_mod_pass<'tcx, T: LateLintPass<'tcx>>(
tcx: TyCtxt<'tcx>,
module_def_id: LocalDefId,
pass: T,
let context = LateContext {
tcx,
- tables: &ty::TypeckTables::empty(None),
+ enclosing_body: None,
+ cached_typeck_tables: Cell::new(None),
param_env: ty::ParamEnv::empty(),
access_levels,
lint_store: unerased_lint_store(tcx),
}
}
-pub fn late_lint_mod<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
+pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx>>(
tcx: TyCtxt<'tcx>,
module_def_id: LocalDefId,
builtin_lints: T,
}
}
-fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, pass: T) {
+fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) {
let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
let krate = tcx.hir().krate();
let context = LateContext {
tcx,
- tables: &ty::TypeckTables::empty(None),
+ enclosing_body: None,
+ cached_typeck_tables: Cell::new(None),
param_env: ty::ParamEnv::empty(),
access_levels,
lint_store: unerased_lint_store(tcx),
})
}
-fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
+fn late_lint_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
let mut passes = unerased_lint_store(tcx).late_passes.iter().map(|p| (p)()).collect::<Vec<_>>();
if !tcx.sess.opts.debugging_opts.no_interleave_lints {
}
/// Performs lint checking on a crate.
-pub fn check_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
+pub fn check_crate<'tcx, T: LateLintPass<'tcx>>(
tcx: TyCtxt<'tcx>,
builtin_lints: impl FnOnce() -> T + Send,
) {