diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index ce08d5d7f2f..dcda4226551 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -959,8 +959,9 @@ pub struct ExpansionData { pub is_trailing_mac: bool, } -type OnExternModLoaded<'a> = - Option<&'a dyn Fn(Ident, Vec, Vec>, Span) -> (Vec, Vec>)>; +type OnExternModLoaded<'a> = Option< + &'a dyn Fn(NodeId, Vec, Vec>, Symbol) -> (Vec, Vec>), +>; /// One of these is made during expansion and incrementally updated as we go; /// when a macro expansion occurs, the resulting nodes have the `backtrace() diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 7604a464be2..ac637b7c7ed 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1108,7 +1108,12 @@ impl InvocationCollectorNode for P { ); if let Some(extern_mod_loaded) = ecx.extern_mod_loaded { - (attrs, items) = extern_mod_loaded(ident, attrs, items, inner_span); + (attrs, items) = extern_mod_loaded( + ecx.current_expansion.lint_node_id, + attrs, + items, + ident.name, + ); } *mod_kind = ModKind::Loaded(items, Inline::No, inner_span); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 6ac73d06868..a1b38b6fb90 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -3,7 +3,7 @@ use crate::proc_macro_decls; use crate::util; use rustc_ast::mut_visit::MutVisitor; -use rustc_ast::{self as ast, visit, DUMMY_NODE_ID}; +use rustc_ast::{self as ast, visit}; use rustc_borrowck as mir_borrowck; use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_ssa::traits::CodegenBackend; @@ -14,7 +14,7 @@ use rustc_errors::{Applicability, ErrorReported, PResult}; use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE}; use rustc_hir::Crate; -use rustc_lint::LintStore; +use rustc_lint::{EarlyCheckNode, LintStore}; use rustc_metadata::creader::CStore; use rustc_metadata::{encode_metadata, EncodedMetadata}; use rustc_middle::arena::Arena; @@ -34,7 +34,7 @@ use rustc_session::lint; use rustc_session::output::{filename_for_input, filename_for_metadata}; use rustc_session::search_paths::PathKind; use rustc_session::{Limit, Session}; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{sym, Symbol}; use rustc_span::{FileName, MultiSpan}; use rustc_trait_selection::traits; use rustc_typeck as typeck; @@ -233,11 +233,11 @@ pub fn register_plugins<'a>( Ok((krate, lint_store)) } -fn pre_expansion_lint( +fn pre_expansion_lint<'a>( sess: &Session, lint_store: &LintStore, registered_tools: &RegisteredTools, - check_node: &ast::Crate, + check_node: impl EarlyCheckNode<'a>, node_name: &str, ) { sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", node_name).run(|| { @@ -322,10 +322,15 @@ pub fn configure_and_expand( }; let registered_tools = resolver.registered_tools().clone(); - let extern_mod_loaded = |ident: Ident, attrs, items, span| { - let krate = ast::Crate { attrs, items, span, id: DUMMY_NODE_ID, is_placeholder: false }; - pre_expansion_lint(sess, lint_store, ®istered_tools, &krate, ident.name.as_str()); - (krate.attrs, krate.items) + let extern_mod_loaded = |node_id, attrs: Vec<_>, items: Vec<_>, name: Symbol| { + pre_expansion_lint( + sess, + lint_store, + ®istered_tools, + (node_id, &*attrs, &*items), + name.as_str(), + ); + (attrs, items) }; let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&extern_mod_loaded)); @@ -507,7 +512,7 @@ pub fn lower_to_hir<'res, 'tcx>( resolver.registered_tools(), lint_buffer, rustc_lint::BuiltinCombinedEarlyLintPass::new(), - &krate, + &*krate, ) }); diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 6cf67922be7..1b2c88867d4 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -16,9 +16,10 @@ use crate::context::{EarlyContext, LintContext, LintStore}; use crate::passes::{EarlyLintPass, EarlyLintPassObject}; -use rustc_ast as ast; -use rustc_ast::visit as ast_visit; +use rustc_ast::ptr::P; +use rustc_ast::visit::{self as ast_visit, Visitor}; use rustc_ast::AstLike; +use rustc_ast::{self as ast, walk_list}; use rustc_middle::ty::RegisteredTools; use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass}; use rustc_session::Session; @@ -32,7 +33,7 @@ macro_rules! run_early_pass { ($cx:expr, $f:ident, $($args:expr),*) => ({ $cx.pass.$f(&$cx.context, $($args),*); }) } -struct EarlyContextAndPass<'a, T: EarlyLintPass> { +pub struct EarlyContextAndPass<'a, T: EarlyLintPass> { context: EarlyContext<'a>, pass: T, } @@ -326,14 +327,65 @@ macro_rules! early_lint_pass_impl { crate::early_lint_methods!(early_lint_pass_impl, []); -fn early_lint_node( +/// Early lints work on different nodes - either on the crate root, or on freshly loaded modules. +/// This trait generalizes over those nodes. +pub trait EarlyCheckNode<'a>: Copy { + fn id(self) -> ast::NodeId; + fn attrs<'b>(self) -> &'b [ast::Attribute] + where + 'a: 'b; + fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>) + where + 'a: 'b; +} + +impl<'a> EarlyCheckNode<'a> for &'a ast::Crate { + fn id(self) -> ast::NodeId { + ast::CRATE_NODE_ID + } + fn attrs<'b>(self) -> &'b [ast::Attribute] + where + 'a: 'b, + { + &self.attrs + } + fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>) + where + 'a: 'b, + { + run_early_pass!(cx, check_crate, self); + ast_visit::walk_crate(cx, self); + run_early_pass!(cx, check_crate_post, self); + } +} + +impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [ast::Attribute], &'a [P]) { + fn id(self) -> ast::NodeId { + self.0 + } + fn attrs<'b>(self) -> &'b [ast::Attribute] + where + 'a: 'b, + { + self.1 + } + fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>) + where + 'a: 'b, + { + walk_list!(cx, visit_attribute, self.1); + walk_list!(cx, visit_item, self.2); + } +} + +fn early_lint_node<'a>( sess: &Session, warn_about_weird_lints: bool, lint_store: &LintStore, registered_tools: &RegisteredTools, buffered: LintBuffer, pass: impl EarlyLintPass, - check_node: &ast::Crate, + check_node: impl EarlyCheckNode<'a>, ) -> LintBuffer { let mut cx = EarlyContextAndPass { context: EarlyContext::new( @@ -346,22 +398,18 @@ fn early_lint_node( pass, }; - cx.with_lint_attrs(ast::CRATE_NODE_ID, &check_node.attrs, |cx| { - run_early_pass!(cx, check_crate, check_node); - ast_visit::walk_crate(cx, check_node); - run_early_pass!(cx, check_crate_post, check_node); - }); + cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx)); cx.context.buffered } -pub fn check_ast_node( +pub fn check_ast_node<'a>( sess: &Session, pre_expansion: bool, lint_store: &LintStore, registered_tools: &RegisteredTools, lint_buffer: Option, builtin_lints: impl EarlyLintPass, - check_node: &ast::Crate, + check_node: impl EarlyCheckNode<'a>, ) { let passes = if pre_expansion { &lint_store.pre_expansion_passes } else { &lint_store.early_passes }; diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 080a38bae66..8afbd462c14 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -5,7 +5,7 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_hir::{intravisit, HirId, CRATE_HIR_ID}; +use rustc_hir::{intravisit, HirId}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::LevelAndSource; use rustc_middle::lint::LintDiagnosticBuilder;