Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 96180ff

Browse files
committedJan 1, 2020
Move late lint machanism in librustc_lint.
1 parent 3a350e1 commit 96180ff

File tree

5 files changed

+486
-455
lines changed

5 files changed

+486
-455
lines changed
 

‎src/librustc/lint/context.rs

Lines changed: 8 additions & 451 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,20 @@
1717
use self::TargetLint::*;
1818

1919
use crate::hir;
20-
use crate::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
21-
use crate::hir::intravisit as hir_visit;
22-
use crate::hir::intravisit::Visitor;
20+
use crate::hir::def_id::{CrateNum, DefId};
2321
use crate::hir::map::{definitions::DisambiguatedDefPathData, DefPathData};
2422
use crate::lint::builtin::BuiltinLintDiagnostics;
2523
use crate::lint::levels::{LintLevelSets, LintLevelsBuilder};
26-
use crate::lint::{EarlyLintPassObject, LateLintPass, LateLintPassObject};
27-
use crate::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId, LintPass};
24+
use crate::lint::{EarlyLintPassObject, LateLintPassObject};
25+
use crate::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
2826
use crate::middle::privacy::AccessLevels;
2927
use crate::session::Session;
3028
use crate::ty::layout::{LayoutError, LayoutOf, TyLayout};
3129
use crate::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
32-
use crate::util::common::time;
3330
use crate::util::nodemap::FxHashMap;
3431

3532
use errors::DiagnosticBuilder;
36-
use rustc_data_structures::sync::{self, join, par_iter, ParallelIterator};
33+
use rustc_data_structures::sync;
3734
use rustc_span::{symbol::Symbol, MultiSpan, Span};
3835
use std::slice;
3936
use syntax::ast;
@@ -57,9 +54,9 @@ pub struct LintStore {
5754
/// necessarily in a sane manner. This is safe though.)
5855
pub pre_expansion_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>,
5956
pub early_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>,
60-
late_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>,
57+
pub late_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>,
6158
/// This is unique in that we construct them per-module, so not once.
62-
late_module_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>,
59+
pub late_module_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>,
6360

6461
/// Lints indexed by name.
6562
by_name: FxHashMap<String, TargetLint>,
@@ -446,9 +443,9 @@ pub struct LateContext<'a, 'tcx> {
446443
pub access_levels: &'a AccessLevels,
447444

448445
/// The store of registered lints and the lint levels.
449-
lint_store: &'tcx LintStore,
446+
pub lint_store: &'tcx LintStore,
450447

451-
last_node_with_lint_attrs: hir::HirId,
448+
pub last_node_with_lint_attrs: hir::HirId,
452449

453450
/// Generic type parameters in scope for the item we are in.
454451
pub generics: Option<&'tcx hir::Generics<'tcx>>,
@@ -457,11 +454,6 @@ pub struct LateContext<'a, 'tcx> {
457454
pub only_module: bool,
458455
}
459456

460-
pub struct LateContextAndPass<'a, 'tcx, T: LateLintPass<'a, 'tcx>> {
461-
context: LateContext<'a, 'tcx>,
462-
pass: T,
463-
}
464-
465457
/// Context for lint checking of the AST, after expansion, before lowering to
466458
/// HIR.
467459
pub struct EarlyContext<'a> {
@@ -578,10 +570,6 @@ impl<'a> EarlyContext<'a> {
578570
}
579571
}
580572

581-
macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
582-
$cx.pass.$f(&$cx.context, $($args),*);
583-
}) }
584-
585573
impl LintContext for LateContext<'_, '_> {
586574
type PassObject = LateLintPassObject;
587575

@@ -783,434 +771,3 @@ impl<'a, 'tcx> LayoutOf for LateContext<'a, 'tcx> {
783771
self.tcx.layout_of(self.param_env.and(ty))
784772
}
785773
}
786-
787-
impl<'a, 'tcx, T: LateLintPass<'a, 'tcx>> LateContextAndPass<'a, 'tcx, T> {
788-
/// Merge the lints specified by any lint attributes into the
789-
/// current lint context, call the provided function, then reset the
790-
/// lints in effect to their previous state.
791-
fn with_lint_attrs<F>(&mut self, id: hir::HirId, attrs: &'tcx [ast::Attribute], f: F)
792-
where
793-
F: FnOnce(&mut Self),
794-
{
795-
let prev = self.context.last_node_with_lint_attrs;
796-
self.context.last_node_with_lint_attrs = id;
797-
self.enter_attrs(attrs);
798-
f(self);
799-
self.exit_attrs(attrs);
800-
self.context.last_node_with_lint_attrs = prev;
801-
}
802-
803-
fn with_param_env<F>(&mut self, id: hir::HirId, f: F)
804-
where
805-
F: FnOnce(&mut Self),
806-
{
807-
let old_param_env = self.context.param_env;
808-
self.context.param_env =
809-
self.context.tcx.param_env(self.context.tcx.hir().local_def_id(id));
810-
f(self);
811-
self.context.param_env = old_param_env;
812-
}
813-
814-
fn process_mod(&mut self, m: &'tcx hir::Mod<'tcx>, s: Span, n: hir::HirId) {
815-
lint_callback!(self, check_mod, m, s, n);
816-
hir_visit::walk_mod(self, m, n);
817-
lint_callback!(self, check_mod_post, m, s, n);
818-
}
819-
820-
fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
821-
debug!("late context: enter_attrs({:?})", attrs);
822-
lint_callback!(self, enter_lint_attrs, attrs);
823-
}
824-
825-
fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
826-
debug!("late context: exit_attrs({:?})", attrs);
827-
lint_callback!(self, exit_lint_attrs, attrs);
828-
}
829-
}
830-
831-
impl<'a, 'tcx, T: LateLintPass<'a, 'tcx>> hir_visit::Visitor<'tcx>
832-
for LateContextAndPass<'a, 'tcx, T>
833-
{
834-
/// Because lints are scoped lexically, we want to walk nested
835-
/// items in the context of the outer item, so enable
836-
/// deep-walking.
837-
fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'tcx> {
838-
hir_visit::NestedVisitorMap::All(&self.context.tcx.hir())
839-
}
840-
841-
fn visit_nested_body(&mut self, body: hir::BodyId) {
842-
let old_tables = self.context.tables;
843-
self.context.tables = self.context.tcx.body_tables(body);
844-
let body = self.context.tcx.hir().body(body);
845-
self.visit_body(body);
846-
self.context.tables = old_tables;
847-
}
848-
849-
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
850-
self.with_lint_attrs(param.hir_id, &param.attrs, |cx| {
851-
lint_callback!(cx, check_param, param);
852-
hir_visit::walk_param(cx, param);
853-
});
854-
}
855-
856-
fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
857-
lint_callback!(self, check_body, body);
858-
hir_visit::walk_body(self, body);
859-
lint_callback!(self, check_body_post, body);
860-
}
861-
862-
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
863-
let generics = self.context.generics.take();
864-
self.context.generics = it.kind.generics();
865-
self.with_lint_attrs(it.hir_id, &it.attrs, |cx| {
866-
cx.with_param_env(it.hir_id, |cx| {
867-
lint_callback!(cx, check_item, it);
868-
hir_visit::walk_item(cx, it);
869-
lint_callback!(cx, check_item_post, it);
870-
});
871-
});
872-
self.context.generics = generics;
873-
}
874-
875-
fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
876-
self.with_lint_attrs(it.hir_id, &it.attrs, |cx| {
877-
cx.with_param_env(it.hir_id, |cx| {
878-
lint_callback!(cx, check_foreign_item, it);
879-
hir_visit::walk_foreign_item(cx, it);
880-
lint_callback!(cx, check_foreign_item_post, it);
881-
});
882-
})
883-
}
884-
885-
fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
886-
lint_callback!(self, check_pat, p);
887-
hir_visit::walk_pat(self, p);
888-
}
889-
890-
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
891-
self.with_lint_attrs(e.hir_id, &e.attrs, |cx| {
892-
lint_callback!(cx, check_expr, e);
893-
hir_visit::walk_expr(cx, e);
894-
lint_callback!(cx, check_expr_post, e);
895-
})
896-
}
897-
898-
fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
899-
// statement attributes are actually just attributes on one of
900-
// - item
901-
// - local
902-
// - expression
903-
// so we keep track of lint levels there
904-
lint_callback!(self, check_stmt, s);
905-
hir_visit::walk_stmt(self, s);
906-
}
907-
908-
fn visit_fn(
909-
&mut self,
910-
fk: hir_visit::FnKind<'tcx>,
911-
decl: &'tcx hir::FnDecl<'tcx>,
912-
body_id: hir::BodyId,
913-
span: Span,
914-
id: hir::HirId,
915-
) {
916-
// Wrap in tables here, not just in visit_nested_body,
917-
// in order for `check_fn` to be able to use them.
918-
let old_tables = self.context.tables;
919-
self.context.tables = self.context.tcx.body_tables(body_id);
920-
let body = self.context.tcx.hir().body(body_id);
921-
lint_callback!(self, check_fn, fk, decl, body, span, id);
922-
hir_visit::walk_fn(self, fk, decl, body_id, span, id);
923-
lint_callback!(self, check_fn_post, fk, decl, body, span, id);
924-
self.context.tables = old_tables;
925-
}
926-
927-
fn visit_variant_data(
928-
&mut self,
929-
s: &'tcx hir::VariantData<'tcx>,
930-
_: ast::Name,
931-
_: &'tcx hir::Generics<'tcx>,
932-
_: hir::HirId,
933-
_: Span,
934-
) {
935-
lint_callback!(self, check_struct_def, s);
936-
hir_visit::walk_struct_def(self, s);
937-
lint_callback!(self, check_struct_def_post, s);
938-
}
939-
940-
fn visit_struct_field(&mut self, s: &'tcx hir::StructField<'tcx>) {
941-
self.with_lint_attrs(s.hir_id, &s.attrs, |cx| {
942-
lint_callback!(cx, check_struct_field, s);
943-
hir_visit::walk_struct_field(cx, s);
944-
})
945-
}
946-
947-
fn visit_variant(
948-
&mut self,
949-
v: &'tcx hir::Variant<'tcx>,
950-
g: &'tcx hir::Generics<'tcx>,
951-
item_id: hir::HirId,
952-
) {
953-
self.with_lint_attrs(v.id, &v.attrs, |cx| {
954-
lint_callback!(cx, check_variant, v);
955-
hir_visit::walk_variant(cx, v, g, item_id);
956-
lint_callback!(cx, check_variant_post, v);
957-
})
958-
}
959-
960-
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
961-
lint_callback!(self, check_ty, t);
962-
hir_visit::walk_ty(self, t);
963-
}
964-
965-
fn visit_name(&mut self, sp: Span, name: ast::Name) {
966-
lint_callback!(self, check_name, sp, name);
967-
}
968-
969-
fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, s: Span, n: hir::HirId) {
970-
if !self.context.only_module {
971-
self.process_mod(m, s, n);
972-
}
973-
}
974-
975-
fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
976-
self.with_lint_attrs(l.hir_id, &l.attrs, |cx| {
977-
lint_callback!(cx, check_local, l);
978-
hir_visit::walk_local(cx, l);
979-
})
980-
}
981-
982-
fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) {
983-
lint_callback!(self, check_block, b);
984-
hir_visit::walk_block(self, b);
985-
lint_callback!(self, check_block_post, b);
986-
}
987-
988-
fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
989-
lint_callback!(self, check_arm, a);
990-
hir_visit::walk_arm(self, a);
991-
}
992-
993-
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
994-
lint_callback!(self, check_generic_param, p);
995-
hir_visit::walk_generic_param(self, p);
996-
}
997-
998-
fn visit_generics(&mut self, g: &'tcx hir::Generics<'tcx>) {
999-
lint_callback!(self, check_generics, g);
1000-
hir_visit::walk_generics(self, g);
1001-
}
1002-
1003-
fn visit_where_predicate(&mut self, p: &'tcx hir::WherePredicate<'tcx>) {
1004-
lint_callback!(self, check_where_predicate, p);
1005-
hir_visit::walk_where_predicate(self, p);
1006-
}
1007-
1008-
fn visit_poly_trait_ref(
1009-
&mut self,
1010-
t: &'tcx hir::PolyTraitRef<'tcx>,
1011-
m: hir::TraitBoundModifier,
1012-
) {
1013-
lint_callback!(self, check_poly_trait_ref, t, m);
1014-
hir_visit::walk_poly_trait_ref(self, t, m);
1015-
}
1016-
1017-
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
1018-
let generics = self.context.generics.take();
1019-
self.context.generics = Some(&trait_item.generics);
1020-
self.with_lint_attrs(trait_item.hir_id, &trait_item.attrs, |cx| {
1021-
cx.with_param_env(trait_item.hir_id, |cx| {
1022-
lint_callback!(cx, check_trait_item, trait_item);
1023-
hir_visit::walk_trait_item(cx, trait_item);
1024-
lint_callback!(cx, check_trait_item_post, trait_item);
1025-
});
1026-
});
1027-
self.context.generics = generics;
1028-
}
1029-
1030-
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
1031-
let generics = self.context.generics.take();
1032-
self.context.generics = Some(&impl_item.generics);
1033-
self.with_lint_attrs(impl_item.hir_id, &impl_item.attrs, |cx| {
1034-
cx.with_param_env(impl_item.hir_id, |cx| {
1035-
lint_callback!(cx, check_impl_item, impl_item);
1036-
hir_visit::walk_impl_item(cx, impl_item);
1037-
lint_callback!(cx, check_impl_item_post, impl_item);
1038-
});
1039-
});
1040-
self.context.generics = generics;
1041-
}
1042-
1043-
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
1044-
lint_callback!(self, check_lifetime, lt);
1045-
hir_visit::walk_lifetime(self, lt);
1046-
}
1047-
1048-
fn visit_path(&mut self, p: &'tcx hir::Path<'tcx>, id: hir::HirId) {
1049-
lint_callback!(self, check_path, p, id);
1050-
hir_visit::walk_path(self, p);
1051-
}
1052-
1053-
fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) {
1054-
lint_callback!(self, check_attribute, attr);
1055-
}
1056-
}
1057-
1058-
struct LateLintPassObjects<'a> {
1059-
lints: &'a mut [LateLintPassObject],
1060-
}
1061-
1062-
#[allow(rustc::lint_pass_impl_without_macro)]
1063-
impl LintPass for LateLintPassObjects<'_> {
1064-
fn name(&self) -> &'static str {
1065-
panic!()
1066-
}
1067-
}
1068-
1069-
macro_rules! expand_late_lint_pass_impl_methods {
1070-
([$a:tt, $hir:tt], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
1071-
$(fn $name(&mut self, context: &LateContext<$a, $hir>, $($param: $arg),*) {
1072-
for obj in self.lints.iter_mut() {
1073-
obj.$name(context, $($param),*);
1074-
}
1075-
})*
1076-
)
1077-
}
1078-
1079-
macro_rules! late_lint_pass_impl {
1080-
([], [$hir:tt], $methods:tt) => (
1081-
impl LateLintPass<'a, $hir> for LateLintPassObjects<'_> {
1082-
expand_late_lint_pass_impl_methods!(['a, $hir], $methods);
1083-
}
1084-
)
1085-
}
1086-
1087-
late_lint_methods!(late_lint_pass_impl, [], ['tcx]);
1088-
1089-
fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
1090-
tcx: TyCtxt<'tcx>,
1091-
module_def_id: DefId,
1092-
pass: T,
1093-
) {
1094-
let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
1095-
1096-
let context = LateContext {
1097-
tcx,
1098-
tables: &ty::TypeckTables::empty(None),
1099-
param_env: ty::ParamEnv::empty(),
1100-
access_levels,
1101-
lint_store: &tcx.lint_store,
1102-
last_node_with_lint_attrs: tcx.hir().as_local_hir_id(module_def_id).unwrap(),
1103-
generics: None,
1104-
only_module: true,
1105-
};
1106-
1107-
let mut cx = LateContextAndPass { context, pass };
1108-
1109-
let (module, span, hir_id) = tcx.hir().get_module(module_def_id);
1110-
cx.process_mod(module, span, hir_id);
1111-
1112-
// Visit the crate attributes
1113-
if hir_id == hir::CRATE_HIR_ID {
1114-
walk_list!(cx, visit_attribute, tcx.hir().attrs(hir::CRATE_HIR_ID));
1115-
}
1116-
}
1117-
1118-
pub fn late_lint_mod<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
1119-
tcx: TyCtxt<'tcx>,
1120-
module_def_id: DefId,
1121-
builtin_lints: T,
1122-
) {
1123-
if tcx.sess.opts.debugging_opts.no_interleave_lints {
1124-
// These passes runs in late_lint_crate with -Z no_interleave_lints
1125-
return;
1126-
}
1127-
1128-
late_lint_mod_pass(tcx, module_def_id, builtin_lints);
1129-
1130-
let mut passes: Vec<_> =
1131-
tcx.lint_store.late_module_passes.iter().map(|pass| (pass)()).collect();
1132-
1133-
if !passes.is_empty() {
1134-
late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] });
1135-
}
1136-
}
1137-
1138-
fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, pass: T) {
1139-
let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
1140-
1141-
let krate = tcx.hir().krate();
1142-
1143-
let context = LateContext {
1144-
tcx,
1145-
tables: &ty::TypeckTables::empty(None),
1146-
param_env: ty::ParamEnv::empty(),
1147-
access_levels,
1148-
lint_store: &tcx.lint_store,
1149-
last_node_with_lint_attrs: hir::CRATE_HIR_ID,
1150-
generics: None,
1151-
only_module: false,
1152-
};
1153-
1154-
let mut cx = LateContextAndPass { context, pass };
1155-
1156-
// Visit the whole crate.
1157-
cx.with_lint_attrs(hir::CRATE_HIR_ID, &krate.attrs, |cx| {
1158-
// since the root module isn't visited as an item (because it isn't an
1159-
// item), warn for it here.
1160-
lint_callback!(cx, check_crate, krate);
1161-
1162-
hir_visit::walk_crate(cx, krate);
1163-
1164-
lint_callback!(cx, check_crate_post, krate);
1165-
})
1166-
}
1167-
1168-
fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
1169-
let mut passes = tcx.lint_store.late_passes.iter().map(|p| (p)()).collect::<Vec<_>>();
1170-
1171-
if !tcx.sess.opts.debugging_opts.no_interleave_lints {
1172-
if !passes.is_empty() {
1173-
late_lint_pass_crate(tcx, LateLintPassObjects { lints: &mut passes[..] });
1174-
}
1175-
1176-
late_lint_pass_crate(tcx, builtin_lints);
1177-
} else {
1178-
for pass in &mut passes {
1179-
time(tcx.sess, &format!("running late lint: {}", pass.name()), || {
1180-
late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
1181-
});
1182-
}
1183-
1184-
let mut passes: Vec<_> =
1185-
tcx.lint_store.late_module_passes.iter().map(|pass| (pass)()).collect();
1186-
1187-
for pass in &mut passes {
1188-
time(tcx.sess, &format!("running late module lint: {}", pass.name()), || {
1189-
late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
1190-
});
1191-
}
1192-
}
1193-
}
1194-
1195-
/// Performs lint checking on a crate.
1196-
pub fn check_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
1197-
tcx: TyCtxt<'tcx>,
1198-
builtin_lints: impl FnOnce() -> T + Send,
1199-
) {
1200-
join(
1201-
|| {
1202-
time(tcx.sess, "crate lints", || {
1203-
// Run whole crate non-incremental lints
1204-
late_lint_crate(tcx, builtin_lints());
1205-
});
1206-
},
1207-
|| {
1208-
time(tcx.sess, "module lints", || {
1209-
// Run per-module lints
1210-
par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
1211-
tcx.ensure().lint_mod(tcx.hir().local_def_id(module));
1212-
});
1213-
});
1214-
},
1215-
);
1216-
}

‎src/librustc/lint/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ use syntax::source_map::{DesugaringKind, ExpnKind, MultiSpan};
3939
use syntax::symbol::Symbol;
4040

4141
pub use crate::lint::context::{
42-
check_crate, late_lint_mod, BufferedEarlyLint, CheckLintNameResult, EarlyContext, LateContext,
43-
LintContext, LintStore,
42+
BufferedEarlyLint, CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore,
4443
};
4544

4645
pub use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintId};

‎src/librustc_interface/passes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
886886
},
887887
{
888888
time(sess, "lint checking", || {
889-
lint::check_crate(tcx, || {
889+
rustc_lint::check_crate(tcx, || {
890890
rustc_lint::BuiltinCombinedLateLintPass::new()
891891
});
892892
});

‎src/librustc_lint/late.rs

Lines changed: 473 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,473 @@
1+
//! Implementation of lint checking.
2+
//!
3+
//! The lint checking is mostly consolidated into one pass which runs
4+
//! after all other analyses. Throughout compilation, lint warnings
5+
//! can be added via the `add_lint` method on the Session structure. This
6+
//! requires a span and an ID of the node that the lint is being added to. The
7+
//! lint isn't actually emitted at that time because it is unknown what the
8+
//! actual lint level at that location is.
9+
//!
10+
//! To actually emit lint warnings/errors, a separate pass is used.
11+
//! A context keeps track of the current state of all lint levels.
12+
//! Upon entering a node of the ast which can modify the lint settings, the
13+
//! previous lint state is pushed onto a stack and the ast is then recursed
14+
//! upon. As the ast is traversed, this keeps track of the current lint level
15+
//! for all lint attributes.
16+
17+
use rustc::hir;
18+
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
19+
use rustc::hir::intravisit as hir_visit;
20+
use rustc::hir::intravisit::Visitor;
21+
use rustc::lint::LateContext;
22+
use rustc::lint::LintPass;
23+
use rustc::lint::{LateLintPass, LateLintPassObject};
24+
use rustc::ty::{self, TyCtxt};
25+
use rustc::util::common::time;
26+
27+
use rustc_data_structures::sync::{join, par_iter, ParallelIterator};
28+
use rustc_span::Span;
29+
use std::slice;
30+
use syntax::ast;
31+
32+
use log::debug;
33+
use syntax::walk_list;
34+
35+
macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
36+
$cx.pass.$f(&$cx.context, $($args),*);
37+
}) }
38+
39+
struct LateContextAndPass<'a, 'tcx, T: LateLintPass<'a, 'tcx>> {
40+
context: LateContext<'a, 'tcx>,
41+
pass: T,
42+
}
43+
44+
impl<'a, 'tcx, T: LateLintPass<'a, 'tcx>> LateContextAndPass<'a, 'tcx, T> {
45+
/// Merge the lints specified by any lint attributes into the
46+
/// current lint context, call the provided function, then reset the
47+
/// lints in effect to their previous state.
48+
fn with_lint_attrs<F>(&mut self, id: hir::HirId, attrs: &'tcx [ast::Attribute], f: F)
49+
where
50+
F: FnOnce(&mut Self),
51+
{
52+
let prev = self.context.last_node_with_lint_attrs;
53+
self.context.last_node_with_lint_attrs = id;
54+
self.enter_attrs(attrs);
55+
f(self);
56+
self.exit_attrs(attrs);
57+
self.context.last_node_with_lint_attrs = prev;
58+
}
59+
60+
fn with_param_env<F>(&mut self, id: hir::HirId, f: F)
61+
where
62+
F: FnOnce(&mut Self),
63+
{
64+
let old_param_env = self.context.param_env;
65+
self.context.param_env =
66+
self.context.tcx.param_env(self.context.tcx.hir().local_def_id(id));
67+
f(self);
68+
self.context.param_env = old_param_env;
69+
}
70+
71+
fn process_mod(&mut self, m: &'tcx hir::Mod<'tcx>, s: Span, n: hir::HirId) {
72+
lint_callback!(self, check_mod, m, s, n);
73+
hir_visit::walk_mod(self, m, n);
74+
lint_callback!(self, check_mod_post, m, s, n);
75+
}
76+
77+
fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
78+
debug!("late context: enter_attrs({:?})", attrs);
79+
lint_callback!(self, enter_lint_attrs, attrs);
80+
}
81+
82+
fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
83+
debug!("late context: exit_attrs({:?})", attrs);
84+
lint_callback!(self, exit_lint_attrs, attrs);
85+
}
86+
}
87+
88+
impl<'a, 'tcx, T: LateLintPass<'a, 'tcx>> hir_visit::Visitor<'tcx>
89+
for LateContextAndPass<'a, 'tcx, T>
90+
{
91+
/// Because lints are scoped lexically, we want to walk nested
92+
/// items in the context of the outer item, so enable
93+
/// deep-walking.
94+
fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'tcx> {
95+
hir_visit::NestedVisitorMap::All(&self.context.tcx.hir())
96+
}
97+
98+
fn visit_nested_body(&mut self, body: hir::BodyId) {
99+
let old_tables = self.context.tables;
100+
self.context.tables = self.context.tcx.body_tables(body);
101+
let body = self.context.tcx.hir().body(body);
102+
self.visit_body(body);
103+
self.context.tables = old_tables;
104+
}
105+
106+
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
107+
self.with_lint_attrs(param.hir_id, &param.attrs, |cx| {
108+
lint_callback!(cx, check_param, param);
109+
hir_visit::walk_param(cx, param);
110+
});
111+
}
112+
113+
fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
114+
lint_callback!(self, check_body, body);
115+
hir_visit::walk_body(self, body);
116+
lint_callback!(self, check_body_post, body);
117+
}
118+
119+
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
120+
let generics = self.context.generics.take();
121+
self.context.generics = it.kind.generics();
122+
self.with_lint_attrs(it.hir_id, &it.attrs, |cx| {
123+
cx.with_param_env(it.hir_id, |cx| {
124+
lint_callback!(cx, check_item, it);
125+
hir_visit::walk_item(cx, it);
126+
lint_callback!(cx, check_item_post, it);
127+
});
128+
});
129+
self.context.generics = generics;
130+
}
131+
132+
fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
133+
self.with_lint_attrs(it.hir_id, &it.attrs, |cx| {
134+
cx.with_param_env(it.hir_id, |cx| {
135+
lint_callback!(cx, check_foreign_item, it);
136+
hir_visit::walk_foreign_item(cx, it);
137+
lint_callback!(cx, check_foreign_item_post, it);
138+
});
139+
})
140+
}
141+
142+
fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
143+
lint_callback!(self, check_pat, p);
144+
hir_visit::walk_pat(self, p);
145+
}
146+
147+
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
148+
self.with_lint_attrs(e.hir_id, &e.attrs, |cx| {
149+
lint_callback!(cx, check_expr, e);
150+
hir_visit::walk_expr(cx, e);
151+
lint_callback!(cx, check_expr_post, e);
152+
})
153+
}
154+
155+
fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
156+
// statement attributes are actually just attributes on one of
157+
// - item
158+
// - local
159+
// - expression
160+
// so we keep track of lint levels there
161+
lint_callback!(self, check_stmt, s);
162+
hir_visit::walk_stmt(self, s);
163+
}
164+
165+
fn visit_fn(
166+
&mut self,
167+
fk: hir_visit::FnKind<'tcx>,
168+
decl: &'tcx hir::FnDecl<'tcx>,
169+
body_id: hir::BodyId,
170+
span: Span,
171+
id: hir::HirId,
172+
) {
173+
// Wrap in tables here, not just in visit_nested_body,
174+
// in order for `check_fn` to be able to use them.
175+
let old_tables = self.context.tables;
176+
self.context.tables = self.context.tcx.body_tables(body_id);
177+
let body = self.context.tcx.hir().body(body_id);
178+
lint_callback!(self, check_fn, fk, decl, body, span, id);
179+
hir_visit::walk_fn(self, fk, decl, body_id, span, id);
180+
lint_callback!(self, check_fn_post, fk, decl, body, span, id);
181+
self.context.tables = old_tables;
182+
}
183+
184+
fn visit_variant_data(
185+
&mut self,
186+
s: &'tcx hir::VariantData<'tcx>,
187+
_: ast::Name,
188+
_: &'tcx hir::Generics<'tcx>,
189+
_: hir::HirId,
190+
_: Span,
191+
) {
192+
lint_callback!(self, check_struct_def, s);
193+
hir_visit::walk_struct_def(self, s);
194+
lint_callback!(self, check_struct_def_post, s);
195+
}
196+
197+
fn visit_struct_field(&mut self, s: &'tcx hir::StructField<'tcx>) {
198+
self.with_lint_attrs(s.hir_id, &s.attrs, |cx| {
199+
lint_callback!(cx, check_struct_field, s);
200+
hir_visit::walk_struct_field(cx, s);
201+
})
202+
}
203+
204+
fn visit_variant(
205+
&mut self,
206+
v: &'tcx hir::Variant<'tcx>,
207+
g: &'tcx hir::Generics<'tcx>,
208+
item_id: hir::HirId,
209+
) {
210+
self.with_lint_attrs(v.id, &v.attrs, |cx| {
211+
lint_callback!(cx, check_variant, v);
212+
hir_visit::walk_variant(cx, v, g, item_id);
213+
lint_callback!(cx, check_variant_post, v);
214+
})
215+
}
216+
217+
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
218+
lint_callback!(self, check_ty, t);
219+
hir_visit::walk_ty(self, t);
220+
}
221+
222+
fn visit_name(&mut self, sp: Span, name: ast::Name) {
223+
lint_callback!(self, check_name, sp, name);
224+
}
225+
226+
fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, s: Span, n: hir::HirId) {
227+
if !self.context.only_module {
228+
self.process_mod(m, s, n);
229+
}
230+
}
231+
232+
fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
233+
self.with_lint_attrs(l.hir_id, &l.attrs, |cx| {
234+
lint_callback!(cx, check_local, l);
235+
hir_visit::walk_local(cx, l);
236+
})
237+
}
238+
239+
fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) {
240+
lint_callback!(self, check_block, b);
241+
hir_visit::walk_block(self, b);
242+
lint_callback!(self, check_block_post, b);
243+
}
244+
245+
fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
246+
lint_callback!(self, check_arm, a);
247+
hir_visit::walk_arm(self, a);
248+
}
249+
250+
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
251+
lint_callback!(self, check_generic_param, p);
252+
hir_visit::walk_generic_param(self, p);
253+
}
254+
255+
fn visit_generics(&mut self, g: &'tcx hir::Generics<'tcx>) {
256+
lint_callback!(self, check_generics, g);
257+
hir_visit::walk_generics(self, g);
258+
}
259+
260+
fn visit_where_predicate(&mut self, p: &'tcx hir::WherePredicate<'tcx>) {
261+
lint_callback!(self, check_where_predicate, p);
262+
hir_visit::walk_where_predicate(self, p);
263+
}
264+
265+
fn visit_poly_trait_ref(
266+
&mut self,
267+
t: &'tcx hir::PolyTraitRef<'tcx>,
268+
m: hir::TraitBoundModifier,
269+
) {
270+
lint_callback!(self, check_poly_trait_ref, t, m);
271+
hir_visit::walk_poly_trait_ref(self, t, m);
272+
}
273+
274+
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
275+
let generics = self.context.generics.take();
276+
self.context.generics = Some(&trait_item.generics);
277+
self.with_lint_attrs(trait_item.hir_id, &trait_item.attrs, |cx| {
278+
cx.with_param_env(trait_item.hir_id, |cx| {
279+
lint_callback!(cx, check_trait_item, trait_item);
280+
hir_visit::walk_trait_item(cx, trait_item);
281+
lint_callback!(cx, check_trait_item_post, trait_item);
282+
});
283+
});
284+
self.context.generics = generics;
285+
}
286+
287+
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
288+
let generics = self.context.generics.take();
289+
self.context.generics = Some(&impl_item.generics);
290+
self.with_lint_attrs(impl_item.hir_id, &impl_item.attrs, |cx| {
291+
cx.with_param_env(impl_item.hir_id, |cx| {
292+
lint_callback!(cx, check_impl_item, impl_item);
293+
hir_visit::walk_impl_item(cx, impl_item);
294+
lint_callback!(cx, check_impl_item_post, impl_item);
295+
});
296+
});
297+
self.context.generics = generics;
298+
}
299+
300+
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
301+
lint_callback!(self, check_lifetime, lt);
302+
hir_visit::walk_lifetime(self, lt);
303+
}
304+
305+
fn visit_path(&mut self, p: &'tcx hir::Path<'tcx>, id: hir::HirId) {
306+
lint_callback!(self, check_path, p, id);
307+
hir_visit::walk_path(self, p);
308+
}
309+
310+
fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) {
311+
lint_callback!(self, check_attribute, attr);
312+
}
313+
}
314+
315+
struct LateLintPassObjects<'a> {
316+
lints: &'a mut [LateLintPassObject],
317+
}
318+
319+
#[allow(rustc::lint_pass_impl_without_macro)]
320+
impl LintPass for LateLintPassObjects<'_> {
321+
fn name(&self) -> &'static str {
322+
panic!()
323+
}
324+
}
325+
326+
macro_rules! expand_late_lint_pass_impl_methods {
327+
([$a:tt, $hir:tt], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
328+
$(fn $name(&mut self, context: &LateContext<$a, $hir>, $($param: $arg),*) {
329+
for obj in self.lints.iter_mut() {
330+
obj.$name(context, $($param),*);
331+
}
332+
})*
333+
)
334+
}
335+
336+
macro_rules! late_lint_pass_impl {
337+
([], [$hir:tt], $methods:tt) => (
338+
impl<'a, $hir> LateLintPass<'a, $hir> for LateLintPassObjects<'_> {
339+
expand_late_lint_pass_impl_methods!(['a, $hir], $methods);
340+
}
341+
)
342+
}
343+
344+
late_lint_methods!(late_lint_pass_impl, [], ['tcx]);
345+
346+
fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
347+
tcx: TyCtxt<'tcx>,
348+
module_def_id: DefId,
349+
pass: T,
350+
) {
351+
let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
352+
353+
let context = LateContext {
354+
tcx,
355+
tables: &ty::TypeckTables::empty(None),
356+
param_env: ty::ParamEnv::empty(),
357+
access_levels,
358+
lint_store: &tcx.lint_store,
359+
last_node_with_lint_attrs: tcx.hir().as_local_hir_id(module_def_id).unwrap(),
360+
generics: None,
361+
only_module: true,
362+
};
363+
364+
let mut cx = LateContextAndPass { context, pass };
365+
366+
let (module, span, hir_id) = tcx.hir().get_module(module_def_id);
367+
cx.process_mod(module, span, hir_id);
368+
369+
// Visit the crate attributes
370+
if hir_id == hir::CRATE_HIR_ID {
371+
walk_list!(cx, visit_attribute, tcx.hir().attrs(hir::CRATE_HIR_ID));
372+
}
373+
}
374+
375+
pub fn late_lint_mod<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
376+
tcx: TyCtxt<'tcx>,
377+
module_def_id: DefId,
378+
builtin_lints: T,
379+
) {
380+
if tcx.sess.opts.debugging_opts.no_interleave_lints {
381+
// These passes runs in late_lint_crate with -Z no_interleave_lints
382+
return;
383+
}
384+
385+
late_lint_mod_pass(tcx, module_def_id, builtin_lints);
386+
387+
let mut passes: Vec<_> =
388+
tcx.lint_store.late_module_passes.iter().map(|pass| (pass)()).collect();
389+
390+
if !passes.is_empty() {
391+
late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] });
392+
}
393+
}
394+
395+
fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, pass: T) {
396+
let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
397+
398+
let krate = tcx.hir().krate();
399+
400+
let context = LateContext {
401+
tcx,
402+
tables: &ty::TypeckTables::empty(None),
403+
param_env: ty::ParamEnv::empty(),
404+
access_levels,
405+
lint_store: &tcx.lint_store,
406+
last_node_with_lint_attrs: hir::CRATE_HIR_ID,
407+
generics: None,
408+
only_module: false,
409+
};
410+
411+
let mut cx = LateContextAndPass { context, pass };
412+
413+
// Visit the whole crate.
414+
cx.with_lint_attrs(hir::CRATE_HIR_ID, &krate.attrs, |cx| {
415+
// since the root module isn't visited as an item (because it isn't an
416+
// item), warn for it here.
417+
lint_callback!(cx, check_crate, krate);
418+
419+
hir_visit::walk_crate(cx, krate);
420+
421+
lint_callback!(cx, check_crate_post, krate);
422+
})
423+
}
424+
425+
fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
426+
let mut passes = tcx.lint_store.late_passes.iter().map(|p| (p)()).collect::<Vec<_>>();
427+
428+
if !tcx.sess.opts.debugging_opts.no_interleave_lints {
429+
if !passes.is_empty() {
430+
late_lint_pass_crate(tcx, LateLintPassObjects { lints: &mut passes[..] });
431+
}
432+
433+
late_lint_pass_crate(tcx, builtin_lints);
434+
} else {
435+
for pass in &mut passes {
436+
time(tcx.sess, &format!("running late lint: {}", pass.name()), || {
437+
late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
438+
});
439+
}
440+
441+
let mut passes: Vec<_> =
442+
tcx.lint_store.late_module_passes.iter().map(|pass| (pass)()).collect();
443+
444+
for pass in &mut passes {
445+
time(tcx.sess, &format!("running late module lint: {}", pass.name()), || {
446+
late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
447+
});
448+
}
449+
}
450+
}
451+
452+
/// Performs lint checking on a crate.
453+
pub fn check_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
454+
tcx: TyCtxt<'tcx>,
455+
builtin_lints: impl FnOnce() -> T + Send,
456+
) {
457+
join(
458+
|| {
459+
time(tcx.sess, "crate lints", || {
460+
// Run whole crate non-incremental lints
461+
late_lint_crate(tcx, builtin_lints());
462+
});
463+
},
464+
|| {
465+
time(tcx.sess, "module lints", || {
466+
// Run per-module lints
467+
par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
468+
tcx.ensure().lint_mod(tcx.hir().local_def_id(module));
469+
});
470+
});
471+
},
472+
);
473+
}

‎src/librustc_lint/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ extern crate rustc_session;
2525
mod array_into_iter;
2626
pub mod builtin;
2727
mod early;
28+
mod late;
2829
mod non_ascii_idents;
2930
mod nonstandard_style;
3031
mod redundant_semicolon;
@@ -59,13 +60,14 @@ use unused::*;
5960
/// Useful for other parts of the compiler.
6061
pub use builtin::SoftLints;
6162
pub use early::check_ast_crate;
63+
pub use late::check_crate;
6264

6365
pub fn provide(providers: &mut Providers<'_>) {
6466
*providers = Providers { lint_mod, ..*providers };
6567
}
6668

6769
fn lint_mod(tcx: TyCtxt<'_>, module_def_id: DefId) {
68-
lint::late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new());
70+
late::late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new());
6971
}
7072

7173
macro_rules! pre_expansion_lint_passes {

0 commit comments

Comments
 (0)
Please sign in to comment.