Skip to content

Commit 753279d

Browse files
committed
Auto merge of rust-lang#116271 - Alexendoo:filter-passes, r=<try>
[experiment] Unbundle late combined pass, filter late passes before linting r? `@ghost`
2 parents 56ada88 + 1d4fb78 commit 753279d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+240
-681
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4095,6 +4095,7 @@ dependencies = [
40954095
"rustc_graphviz",
40964096
"rustc_hir",
40974097
"rustc_index",
4098+
"rustc_lint_defs",
40984099
"rustc_macros",
40994100
"rustc_query_system",
41004101
"rustc_serialize",

compiler/rustc_lint/src/builtin.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@
77
//! To add a new lint to rustc, declare it here using `declare_lint!()`.
88
//! Then add code to emit the new lint in the appropriate circumstances.
99
//! You can do that in an existing `LintPass` if it makes sense, or in a
10-
//! new `LintPass`, or using `Session::add_lint` elsewhere in the
11-
//! compiler. Only do the latter if the check can't be written cleanly as a
12-
//! `LintPass` (also, note that such lints will need to be defined in
13-
//! `rustc_session::lint::builtin`, not here).
10+
//! new `LintPass`.
1411
//!
1512
//! If you define a new `EarlyLintPass`, you will also need to add it to the
1613
//! `add_early_builtin!` or `add_early_builtin_with_new!` invocation in
@@ -39,13 +36,14 @@ use crate::{
3936
BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
4037
BuiltinWhileTrue, SuggestChangingAssocTypes,
4138
},
42-
EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
39+
EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, LintId,
4340
};
4441
use rustc_ast::attr;
4542
use rustc_ast::tokenstream::{TokenStream, TokenTree};
4643
use rustc_ast::visit::{FnCtxt, FnKind};
4744
use rustc_ast::{self as ast, *};
4845
use rustc_ast_pretty::pprust::{self, expr_to_string};
46+
use rustc_data_structures::fx::FxHashSet;
4947
use rustc_errors::{Applicability, DecorateLint, MultiSpan};
5048
use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
5149
use rustc_hir as hir;
@@ -1523,6 +1521,9 @@ declare_lint_pass!(
15231521
/// unused within this crate, even though downstream crates can't use it
15241522
/// without producing an error.
15251523
UnusedBrokenConst => []
1524+
fn is_enabled(&self, _: &FxHashSet<LintId>) -> bool {
1525+
true
1526+
}
15261527
);
15271528

15281529
impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst {

compiler/rustc_lint/src/context.rs

+12
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,9 @@ pub struct LateContext<'tcx> {
509509

510510
/// We are only looking at one module
511511
pub only_module: bool,
512+
513+
#[cfg(debug_assertions)]
514+
pub(super) permitted_lints: Cell<Option<&'static [&'static str]>>,
512515
}
513516

514517
/// Context for lint checking of the AST, after expansion, before lowering to HIR.
@@ -1067,6 +1070,15 @@ impl<'tcx> LintContext for LateContext<'tcx> {
10671070
&'b mut DiagnosticBuilder<'a, ()>,
10681071
) -> &'b mut DiagnosticBuilder<'a, ()>,
10691072
) {
1073+
#[cfg(debug_assertions)]
1074+
if let Some(permitted) = self.permitted_lints.get() {
1075+
assert!(
1076+
permitted.contains(&lint.name),
1077+
"unexpected lint {} emitted from pass. permitted: {permitted:?}",
1078+
lint.name
1079+
);
1080+
}
1081+
10701082
let hir_id = self.last_node_with_lint_attrs;
10711083

10721084
match span {

compiler/rustc_lint/src/internal.rs

+5-13
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSe
1313
use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
1414
use rustc_middle::ty;
1515
use rustc_session::{declare_lint_pass, declare_tool_lint};
16-
use rustc_span::hygiene::{ExpnKind, MacroKind};
1716
use rustc_span::symbol::{kw, sym, Symbol};
1817
use rustc_span::Span;
1918

@@ -284,18 +283,11 @@ impl EarlyLintPass for LintPassImpl {
284283
if let ast::ItemKind::Impl(box ast::Impl { of_trait: Some(lint_pass), .. }) = &item.kind {
285284
if let Some(last) = lint_pass.path.segments.last() {
286285
if last.ident.name == sym::LintPass {
287-
let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
288-
let call_site = expn_data.call_site;
289-
if expn_data.kind != ExpnKind::Macro(MacroKind::Bang, sym::impl_lint_pass)
290-
&& call_site.ctxt().outer_expn_data().kind
291-
!= ExpnKind::Macro(MacroKind::Bang, sym::declare_lint_pass)
292-
{
293-
cx.emit_spanned_lint(
294-
LINT_PASS_IMPL_WITHOUT_MACRO,
295-
lint_pass.path.span,
296-
LintPassByHand,
297-
);
298-
}
286+
cx.emit_spanned_lint(
287+
LINT_PASS_IMPL_WITHOUT_MACRO,
288+
lint_pass.path.span,
289+
LintPassByHand,
290+
);
299291
}
300292
}
301293
}

compiler/rustc_lint/src/late.rs

+76-22
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,16 @@
1414
//! upon. As the ast is traversed, this keeps track of the current lint level
1515
//! for all lint attributes.
1616
17-
use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore};
17+
use crate::{passes::LateLintPassObject, LateContext, LateLintPass, Level, LintId, LintStore};
1818
use rustc_ast as ast;
19+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1920
use rustc_data_structures::stack::ensure_sufficient_stack;
2021
use rustc_data_structures::sync::join;
2122
use rustc_hir as hir;
2223
use rustc_hir::def_id::{LocalDefId, LocalModDefId};
2324
use rustc_hir::intravisit as hir_visit;
2425
use rustc_middle::hir::nested_filter;
26+
use rustc_middle::lint::{reveal_actual_level, LintLevelSource};
2527
use rustc_middle::ty::{self, TyCtxt};
2628
use rustc_session::lint::LintPass;
2729
use rustc_span::Span;
@@ -315,8 +317,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
315317

316318
// Combines multiple lint passes into a single pass, at runtime. Each
317319
// `check_foo` method in `$methods` within this pass simply calls `check_foo`
318-
// once per `$pass`. Compare with `declare_combined_late_lint_pass`, which is
319-
// similar, but combines lint passes at compile time.
320+
// once per `$pass`.
320321
struct RuntimeCombinedLateLintPass<'a, 'tcx> {
321322
passes: &'a mut [LateLintPassObject<'tcx>],
322323
}
@@ -333,6 +334,8 @@ macro_rules! impl_late_lint_pass {
333334
impl<'tcx> LateLintPass<'tcx> for RuntimeCombinedLateLintPass<'_, 'tcx> {
334335
$(fn $f(&mut self, context: &LateContext<'tcx>, $($param: $arg),*) {
335336
for pass in self.passes.iter_mut() {
337+
#[cfg(debug_assertions)]
338+
context.permitted_lints.set(pass.lint_names());
336339
pass.$f(context, $($param),*);
337340
}
338341
})*
@@ -342,11 +345,7 @@ macro_rules! impl_late_lint_pass {
342345

343346
crate::late_lint_methods!(impl_late_lint_pass, []);
344347

345-
pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
346-
tcx: TyCtxt<'tcx>,
347-
module_def_id: LocalModDefId,
348-
builtin_lints: T,
349-
) {
348+
pub fn late_lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
350349
let context = LateContext {
351350
tcx,
352351
enclosing_body: None,
@@ -357,20 +356,20 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
357356
last_node_with_lint_attrs: tcx.hir().local_def_id_to_hir_id(module_def_id),
358357
generics: None,
359358
only_module: true,
359+
#[cfg(debug_assertions)]
360+
permitted_lints: Cell::new(None),
360361
};
361362

362-
// Note: `passes` is often empty. In that case, it's faster to run
363-
// `builtin_lints` directly rather than bundling it up into the
364-
// `RuntimeCombinedLateLintPass`.
365-
let mut passes: Vec<_> =
366-
unerased_lint_store(tcx).late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
367-
if passes.is_empty() {
368-
late_lint_mod_inner(tcx, module_def_id, context, builtin_lints);
369-
} else {
370-
passes.push(Box::new(builtin_lints));
371-
let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
372-
late_lint_mod_inner(tcx, module_def_id, context, pass);
373-
}
363+
let enabled_lints = tcx.enabled_lints(());
364+
365+
let mut passes: Vec<_> = unerased_lint_store(tcx)
366+
.late_module_passes
367+
.iter()
368+
.map(|mk_pass| (mk_pass)(tcx))
369+
.filter(|pass| pass.is_enabled(enabled_lints))
370+
.collect();
371+
let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
372+
late_lint_mod_inner(tcx, module_def_id, context, pass);
374373
}
375374

376375
fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>(
@@ -398,9 +397,18 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>(
398397
}
399398

400399
fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
400+
// Trigger check for duplicate diagnostic items
401+
let _ = tcx.all_diagnostic_items(());
402+
403+
let enabled_lints = tcx.enabled_lints(());
404+
401405
// Note: `passes` is often empty.
402-
let mut passes: Vec<_> =
403-
unerased_lint_store(tcx).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
406+
let mut passes: Vec<_> = unerased_lint_store(tcx)
407+
.late_passes
408+
.iter()
409+
.map(|mk_pass| (mk_pass)(tcx))
410+
.filter(|pass| pass.is_enabled(enabled_lints))
411+
.collect();
404412

405413
if passes.is_empty() {
406414
return;
@@ -416,6 +424,8 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
416424
last_node_with_lint_attrs: hir::CRATE_HIR_ID,
417425
generics: None,
418426
only_module: false,
427+
#[cfg(debug_assertions)]
428+
permitted_lints: Cell::new(None),
419429
};
420430

421431
let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
@@ -456,3 +466,47 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) {
456466
},
457467
);
458468
}
469+
470+
pub(crate) fn enabled_lints(tcx: TyCtxt<'_>) -> FxHashSet<LintId> {
471+
let get_level = |spec: Option<&FxHashMap<_, _>>, lint| match spec.and_then(|m| m.get(&lint)) {
472+
Some(&(level, source)) => (Some(level), source),
473+
None => (None, LintLevelSource::Default),
474+
};
475+
let may_lint_shallow = |spec: Option<&FxHashMap<_, _>>, level, mut source, lint| {
476+
let actual =
477+
reveal_actual_level(level, &mut source, tcx.sess, lint, |lint| get_level(spec, lint));
478+
479+
actual > Level::Allow
480+
};
481+
482+
let root_lints =
483+
tcx.shallow_lint_levels_on(hir::CRATE_OWNER_ID).specs.get(&hir::CRATE_HIR_ID.local_id);
484+
485+
let mut enabled: FxHashSet<_> = unerased_lint_store(tcx)
486+
.get_lints()
487+
.iter()
488+
.map(|lint| LintId::of(lint))
489+
.filter(|&lint| {
490+
let (level, source) = get_level(root_lints, lint);
491+
may_lint_shallow(root_lints, level, source, lint)
492+
})
493+
.collect();
494+
495+
for (def_id, maybe_owner) in tcx.hir().krate().owners.iter_enumerated() {
496+
if let hir::MaybeOwner::Owner(_) = maybe_owner {
497+
enabled.extend(
498+
tcx.shallow_lint_levels_on(hir::OwnerId { def_id })
499+
.specs
500+
.values()
501+
.flat_map(|spec| {
502+
spec.iter().filter(|&(&lint, &(level, source))| {
503+
may_lint_shallow(Some(spec), Some(level), source, lint)
504+
})
505+
})
506+
.map(|(&lint, _)| lint),
507+
);
508+
}
509+
}
510+
511+
enabled
512+
}

0 commit comments

Comments
 (0)