Skip to content

Commit

Permalink
Rollup merge of #91526 - petrochenkov:earlint, r=cjgillot
Browse files Browse the repository at this point in the history
rustc_lint: Some early linting refactorings

The first one removes and renames some fields and methods from `EarlyContext`.

The second one uses the set of registered tools (for tool attributes and tool lints) in a more centralized way.

The third one removes creation of a fake `ast::Crate` from `fn pre_expansion_lint`.
Pre-expansion linting is done with per-module granularity on freshly loaded modules, and it previously synthesized an `ast::Crate` to visit non-root modules, now they are visited as modules.
The node ID used for pre-expansion linting is also made more precise (the loaded module ID is used).
  • Loading branch information
matthiaskrgr authored Jan 23, 2022
2 parents 84322ef + 67cccaf commit 89baf0f
Show file tree
Hide file tree
Showing 41 changed files with 285 additions and 229 deletions.
32 changes: 22 additions & 10 deletions compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream};
use rustc_ast::visit::{AssocCtxt, Visitor};
use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind};
use rustc_attr::{self as attr, Deprecation, Stability};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{self, Lrc};
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported};
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
Expand Down Expand Up @@ -920,8 +920,25 @@ pub trait ResolverExpand {
/// we generated proc macros harnesses, so that we can map
/// HIR proc macros items back to their harness items.
fn declare_proc_macro(&mut self, id: NodeId);

/// Tools registered with `#![register_tool]` and used by tool attributes and lints.
fn registered_tools(&self) -> &FxHashSet<Ident>;
}

pub trait LintStoreExpand {
fn pre_expansion_lint(
&self,
sess: &Session,
registered_tools: &FxHashSet<Ident>,
node_id: NodeId,
attrs: &[Attribute],
items: &[P<Item>],
name: &str,
);
}

type LintStoreExpandDyn<'a> = Option<&'a (dyn LintStoreExpand + 'a)>;

#[derive(Clone, Default)]
pub struct ModuleData {
/// Path to the module starting from the crate name, like `my_crate::foo::bar`.
Expand Down Expand Up @@ -956,9 +973,6 @@ pub struct ExpansionData {
pub is_trailing_mac: bool,
}

type OnExternModLoaded<'a> =
Option<&'a dyn Fn(Ident, Vec<Attribute>, Vec<P<Item>>, Span) -> (Vec<Attribute>, Vec<P<Item>>)>;

/// One of these is made during expansion and incrementally updated as we go;
/// when a macro expansion occurs, the resulting nodes have the `backtrace()
/// -> expn_data` of their expansion context stored into their span.
Expand All @@ -973,10 +987,8 @@ pub struct ExtCtxt<'a> {
/// (or during eager expansion, but that's a hack).
pub force_mode: bool,
pub expansions: FxHashMap<Span, Vec<String>>,
/// Called directly after having parsed an external `mod foo;` in expansion.
///
/// `Ident` is the module name.
pub(super) extern_mod_loaded: OnExternModLoaded<'a>,
/// Used for running pre-expansion lints on freshly loaded modules.
pub(super) lint_store: LintStoreExpandDyn<'a>,
/// When we 'expand' an inert attribute, we leave it
/// in the AST, but insert it here so that we know
/// not to expand it again.
Expand All @@ -988,14 +1000,14 @@ impl<'a> ExtCtxt<'a> {
sess: &'a Session,
ecfg: expand::ExpansionConfig<'a>,
resolver: &'a mut dyn ResolverExpand,
extern_mod_loaded: OnExternModLoaded<'a>,
lint_store: LintStoreExpandDyn<'a>,
) -> ExtCtxt<'a> {
ExtCtxt {
sess,
ecfg,
reduced_recursion_limit: None,
resolver,
extern_mod_loaded,
lint_store,
root_path: PathBuf::new(),
current_expansion: ExpansionData {
id: LocalExpnId::ROOT,
Expand Down
13 changes: 10 additions & 3 deletions compiler/rustc_expand/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1097,7 +1097,7 @@ impl InvocationCollectorNode for P<ast::Item> {
ModKind::Unloaded => {
// We have an outline `mod foo;` so we need to parse the file.
let old_attrs_len = attrs.len();
let ParsedExternalMod { mut items, inner_span, file_path, dir_path, dir_ownership } =
let ParsedExternalMod { items, inner_span, file_path, dir_path, dir_ownership } =
parse_external_mod(
&ecx.sess,
ident,
Expand All @@ -1107,8 +1107,15 @@ impl InvocationCollectorNode for P<ast::Item> {
&mut attrs,
);

if let Some(extern_mod_loaded) = ecx.extern_mod_loaded {
(attrs, items) = extern_mod_loaded(ident, attrs, items, inner_span);
if let Some(lint_store) = ecx.lint_store {
lint_store.pre_expansion_lint(
ecx.sess,
ecx.resolver.registered_tools(),
ecx.current_expansion.lint_node_id,
&attrs,
&items,
ident.name.as_str(),
);
}

*mod_kind = ModKind::Loaded(items, Inline::No, inner_span);
Expand Down
67 changes: 40 additions & 27 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,24 @@ 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;
use rustc_data_structures::parallel;
use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::{Applicability, ErrorReported, PResult};
use rustc_expand::base::ExtCtxt;
use rustc_expand::base::{ExtCtxt, LintStoreExpand, 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;
use rustc_middle::dep_graph::DepGraph;
use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, ResolverOutputs, TyCtxt};
use rustc_mir_build as mir_build;
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
use rustc_passes::{self, hir_stats, layout_test};
Expand All @@ -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;
Expand Down Expand Up @@ -233,26 +233,43 @@ pub fn register_plugins<'a>(
Ok((krate, lint_store))
}

fn pre_expansion_lint(
fn pre_expansion_lint<'a>(
sess: &Session,
lint_store: &LintStore,
krate: &ast::Crate,
crate_attrs: &[ast::Attribute],
crate_name: &str,
registered_tools: &RegisteredTools,
check_node: impl EarlyCheckNode<'a>,
node_name: &str,
) {
sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", crate_name).run(|| {
rustc_lint::check_ast_crate(
sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", node_name).run(|| {
rustc_lint::check_ast_node(
sess,
lint_store,
krate,
crate_attrs,
true,
lint_store,
registered_tools,
None,
rustc_lint::BuiltinCombinedPreExpansionLintPass::new(),
check_node,
);
});
}

// Cannot implement directly for `LintStore` due to trait coherence.
struct LintStoreExpandImpl<'a>(&'a LintStore);

impl LintStoreExpand for LintStoreExpandImpl<'_> {
fn pre_expansion_lint(
&self,
sess: &Session,
registered_tools: &RegisteredTools,
node_id: ast::NodeId,
attrs: &[ast::Attribute],
items: &[rustc_ast::ptr::P<ast::Item>],
name: &str,
) {
pre_expansion_lint(sess, self.0, registered_tools, (node_id, attrs, items), name);
}
}

/// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins,
/// syntax expansion, secondary `cfg` expansion, synthesis of a test
/// harness if one is to be provided, injection of a dependency on the
Expand All @@ -265,7 +282,7 @@ pub fn configure_and_expand(
resolver: &mut Resolver<'_>,
) -> Result<ast::Crate> {
tracing::trace!("configure_and_expand");
pre_expansion_lint(sess, lint_store, &krate, &krate.attrs, crate_name);
pre_expansion_lint(sess, lint_store, resolver.registered_tools(), &krate, crate_name);
rustc_builtin_macros::register_builtin_macros(resolver);

krate = sess.time("crate_injection", || {
Expand Down Expand Up @@ -321,13 +338,8 @@ pub fn configure_and_expand(
..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string())
};

let crate_attrs = krate.attrs.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, &krate, &crate_attrs, ident.name.as_str());
(krate.attrs, krate.items)
};
let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&extern_mod_loaded));
let lint_store = LintStoreExpandImpl(lint_store);
let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&lint_store));

// Expand macros now!
let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
Expand Down Expand Up @@ -499,14 +511,15 @@ pub fn lower_to_hir<'res, 'tcx>(
);

sess.time("early_lint_checks", || {
rustc_lint::check_ast_crate(
let lint_buffer = Some(std::mem::take(resolver.lint_buffer()));
rustc_lint::check_ast_node(
sess,
lint_store,
&krate,
&krate.attrs,
false,
Some(std::mem::take(resolver.lint_buffer())),
lint_store,
resolver.registered_tools(),
lint_buffer,
rustc_lint::BuiltinCombinedEarlyLintPass::new(),
&*krate,
)
});

Expand Down
14 changes: 7 additions & 7 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -912,7 +912,7 @@ declare_lint_pass!(

impl EarlyLintPass for AnonymousParameters {
fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
if cx.sess.edition() != Edition::Edition2015 {
if cx.sess().edition() != Edition::Edition2015 {
// This is a hard error in future editions; avoid linting and erroring
return;
}
Expand All @@ -921,7 +921,7 @@ impl EarlyLintPass for AnonymousParameters {
if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
if ident.name == kw::Empty {
cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| {
let ty_snip = cx.sess.source_map().span_to_snippet(arg.ty.span);
let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);

let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
(snip.as_str(), Applicability::MachineApplicable)
Expand Down Expand Up @@ -1775,7 +1775,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
};
if join.edition() >= Edition::Edition2021 {
let mut err =
rustc_errors::struct_span_err!(cx.sess, pat.span, E0783, "{}", msg,);
rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,);
err.span_suggestion(
pat.span,
suggestion,
Expand All @@ -1799,7 +1799,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
let replace = "..=".to_owned();
if join.edition() >= Edition::Edition2021 {
let mut err =
rustc_errors::struct_span_err!(cx.sess, pat.span, E0783, "{}", msg,);
rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,);
err.span_suggestion_short(
join,
suggestion,
Expand Down Expand Up @@ -1983,7 +1983,7 @@ impl KeywordIdents {
UnderMacro(under_macro): UnderMacro,
ident: Ident,
) {
let next_edition = match cx.sess.edition() {
let next_edition = match cx.sess().edition() {
Edition::Edition2015 => {
match ident.name {
kw::Async | kw::Await | kw::Try => Edition::Edition2018,
Expand Down Expand Up @@ -2011,7 +2011,7 @@ impl KeywordIdents {
};

// Don't lint `r#foo`.
if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
if cx.sess().parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
return;
}

Expand Down Expand Up @@ -2379,7 +2379,7 @@ declare_lint_pass!(

impl EarlyLintPass for IncompleteFeatures {
fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
let features = cx.sess.features_untracked();
let features = cx.sess().features_untracked();
features
.declared_lang_features
.iter()
Expand Down
Loading

0 comments on commit 89baf0f

Please sign in to comment.