diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5d78d914b6d7f..91fcb5d266a98 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -436,6 +436,7 @@ fn compute_hir_hash( pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { let sess = tcx.sess; tcx.ensure().output_filenames(()); + let _ = tcx.early_lint_checks(()); // Borrows `resolver_for_lowering`. let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal(); let ast_index = index_crate(&resolver.node_id_to_def_id, &krate); diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 464ddae476a5e..e321a9847ba06 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -331,6 +331,7 @@ fn run_compiler( if let Some(ppm) = &sess.opts.pretty { if ppm.needs_ast_map() { queries.global_ctxt()?.enter(|tcx| { + tcx.ensure().early_lint_checks(()); pretty::print_after_hir_lowering(tcx, *ppm); Ok(()) })?; diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 22bc90f5cac2e..713e4fbbdce23 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -12,13 +12,13 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; use rustc_attr::{self as attr, Deprecation, Stability}; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{ Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan, PResult, }; use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; -use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics}; +use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, RegisteredTools}; use rustc_parse::{self, parser, MACRO_ARGUMENTS}; use rustc_session::errors::report_lit_error; use rustc_session::{parse::ParseSess, Limit, Session}; @@ -947,14 +947,14 @@ pub trait ResolverExpand { 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; + fn registered_tools(&self) -> &RegisteredTools; } pub trait LintStoreExpand { fn pre_expansion_lint( &self, sess: &Session, - registered_tools: &FxHashSet, + registered_tools: &RegisteredTools, node_id: NodeId, attrs: &[Attribute], items: &[P], diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 81c1d665ef072..4a02981f9543d 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -11,7 +11,7 @@ use rustc_data_structures::parallel; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_errors::PResult; -use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand}; +use rustc_expand::base::{ExtCtxt, LintStoreExpand}; use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE}; use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintStore}; use rustc_metadata::creader::CStore; @@ -178,7 +178,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) let sess = tcx.sess; let lint_store = unerased_lint_store(tcx); let crate_name = tcx.crate_name(LOCAL_CRATE); - pre_expansion_lint(sess, lint_store, resolver.registered_tools(), &krate, crate_name); + pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), &krate, crate_name); rustc_builtin_macros::register_builtin_macros(resolver); krate = sess.time("crate_injection", || { @@ -302,6 +302,16 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) // Done with macro expansion! + resolver.resolve_crate(&krate); + + krate +} + +fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { + let sess = tcx.sess; + let (resolver, krate) = &*tcx.resolver_for_lowering(()).borrow(); + let mut lint_buffer = resolver.lint_buffer.steal(); + if sess.opts.unstable_opts.input_stats { eprintln!("Post-expansion node count: {}", count_nodes(&krate)); } @@ -310,8 +320,6 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS", "ast-stats-2"); } - resolver.resolve_crate(&krate); - // Needs to go *after* expansion to be able to check the results of macro expansion. sess.time("complete_gated_feature_checking", || { rustc_ast_passes::feature_gate::check_crate(&krate, sess); @@ -321,7 +329,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) sess.parse_sess.buffered_lints.with_lock(|buffered_lints| { info!("{} parse sess buffered_lints", buffered_lints.len()); for early_lint in buffered_lints.drain(..) { - resolver.lint_buffer().add_early_lint(early_lint); + lint_buffer.add_early_lint(early_lint); } }); @@ -340,20 +348,16 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) } }); - sess.time("early_lint_checks", || { - let lint_buffer = Some(std::mem::take(resolver.lint_buffer())); - rustc_lint::check_ast_node( - sess, - false, - lint_store, - resolver.registered_tools(), - lint_buffer, - rustc_lint::BuiltinCombinedEarlyLintPass::new(), - &krate, - ) - }); - - krate + let lint_store = unerased_lint_store(tcx); + rustc_lint::check_ast_node( + sess, + false, + lint_store, + tcx.registered_tools(()), + Some(lint_buffer), + rustc_lint::BuiltinCombinedEarlyLintPass::new(), + &**krate, + ) } // Returns all the paths that correspond to generated files. @@ -557,6 +561,7 @@ fn resolver_for_lowering<'tcx>( (): (), ) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc)> { let arenas = Resolver::arenas(); + let _ = tcx.registered_tools(()); // Uses `crate_for_resolver`. let krate = tcx.crate_for_resolver(()).steal(); let mut resolver = Resolver::new(tcx, &krate, &arenas); let krate = configure_and_expand(krate, &mut resolver); @@ -629,6 +634,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { providers.hir_crate = rustc_ast_lowering::lower_to_hir; providers.output_filenames = output_filenames; providers.resolver_for_lowering = resolver_for_lowering; + providers.early_lint_checks = early_lint_checks; proc_macro_decls::provide(providers); rustc_const_eval::provide(providers); rustc_middle::hir::provide(providers); @@ -637,6 +643,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { rustc_mir_transform::provide(providers); rustc_monomorphize::provide(providers); rustc_privacy::provide(providers); + rustc_resolve::provide(providers); rustc_hir_analysis::provide(providers); rustc_hir_typeck::provide(providers); ty::provide(providers); diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index bc7488fab4a5c..a76229dd3524b 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -128,7 +128,7 @@ fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExp }, warn_about_weird_lints: false, store, - registered_tools: &tcx.resolutions(()).registered_tools, + registered_tools: &tcx.registered_tools(()), }; builder.add_command_line(); @@ -156,7 +156,7 @@ fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLe }, warn_about_weird_lints: false, store, - registered_tools: &tcx.resolutions(()).registered_tools, + registered_tools: &tcx.registered_tools(()), }; if owner == hir::CRATE_OWNER_ID { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 6efbf5ce9eef3..5e3225b74ac00 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -8,7 +8,7 @@ extern crate rustc_macros; pub use self::Level::*; use rustc_ast::node_id::NodeId; use rustc_ast::{AttrId, Attribute}; -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_error_messages::{DiagnosticMessage, MultiSpan}; use rustc_hir::HashStableContext; @@ -526,6 +526,7 @@ pub enum BuiltinLintDiagnostics { /// Lints that are buffered up early on in the `Session` before the /// `LintLevels` is calculated. +#[derive(Debug)] pub struct BufferedEarlyLint { /// The span of code that we are linting on. pub span: MultiSpan, @@ -544,7 +545,7 @@ pub struct BufferedEarlyLint { pub diagnostic: BuiltinLintDiagnostics, } -#[derive(Default)] +#[derive(Default, Debug)] pub struct LintBuffer { pub map: FxIndexMap>, } @@ -594,6 +595,8 @@ impl LintBuffer { } } +pub type RegisteredTools = FxIndexSet; + /// Declares a static item of type `&'static Lint`. /// /// See for diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index d4019b5bf17eb..98b976176ffc6 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -107,6 +107,7 @@ macro_rules! arena_types { // (during lowering) and the `librustc_middle` arena (for decoding MIR) [decode] asm_template: rustc_ast::InlineAsmTemplatePiece, [decode] used_trait_imports: rustc_data_structures::unord::UnordSet, + [decode] registered_tools: rustc_middle::ty::RegisteredTools, [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet, [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d4435a54b4ab6..05f6531a7c4b1 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -26,6 +26,15 @@ rustc_queries! { desc { "triggering a delay span bug" } } + query registered_tools(_: ()) -> &'tcx ty::RegisteredTools { + arena_cache + desc { "compute registered tools for crate" } + } + + query early_lint_checks(_: ()) -> () { + desc { "perform lints prior to macro expansion" } + } + query resolutions(_: ()) -> &'tcx ty::ResolverGlobalCtxt { feedable no_hash diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 17262a0be243c..9894baa9e18cc 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -34,6 +34,7 @@ use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::steal::Steal; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; @@ -44,6 +45,8 @@ use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; use rustc_serialize::{Decodable, Encodable}; +use rustc_session::lint::LintBuffer; +pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, ExpnKind, Span}; @@ -148,8 +151,6 @@ mod typeck_results; // Data types -pub type RegisteredTools = FxHashSet; - pub struct ResolverOutputs { pub global_ctxt: ResolverGlobalCtxt, pub ast_lowering: ResolverAstLowering, @@ -179,7 +180,6 @@ pub struct ResolverGlobalCtxt { /// Mapping from ident span to path span for paths that don't exist as written, but that /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. pub confused_type_with_std_module: FxHashMap, - pub registered_tools: RegisteredTools, pub doc_link_resolutions: FxHashMap, pub doc_link_traits_in_scope: FxHashMap>, pub all_macro_rules: FxHashMap>, @@ -213,6 +213,9 @@ pub struct ResolverAstLowering { pub builtin_macro_kinds: FxHashMap, /// List functions and methods for which lifetime elision was successful. pub lifetime_elision_allowed: FxHashSet, + + /// Lints that were emitted by the resolver and early lints. + pub lint_buffer: Steal, } #[derive(Clone, Copy, Debug)] diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 7a1f14f71f215..13d4c01f25990 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -27,6 +27,7 @@ use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID}; use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; +use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{Lrc, MappedReadGuard}; use rustc_errors::{ Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, SubdiagnosticMessage, @@ -966,7 +967,7 @@ pub struct Resolver<'a, 'tcx> { /// A small map keeping true kinds of built-in macros that appear to be fn-like on /// the surface (`macro` items in libcore), but are actually attributes or derives. builtin_macro_kinds: FxHashMap, - registered_tools: RegisteredTools, + registered_tools: &'tcx RegisteredTools, macro_use_prelude: FxHashMap>, macro_map: FxHashMap, dummy_ext_bang: Lrc, @@ -1241,7 +1242,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - let registered_tools = macros::registered_tools(tcx.sess, &krate.attrs); + let registered_tools = tcx.registered_tools(()); let features = tcx.sess.features_untracked(); @@ -1424,7 +1425,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { trait_impls: self.trait_impls, proc_macros, confused_type_with_std_module, - registered_tools: self.registered_tools, doc_link_resolutions: self.doc_link_resolutions, doc_link_traits_in_scope: self.doc_link_traits_in_scope, all_macro_rules: self.all_macro_rules, @@ -1442,6 +1442,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { trait_map: self.trait_map, builtin_macro_kinds: self.builtin_macro_kinds, lifetime_elision_allowed: self.lifetime_elision_allowed, + lint_buffer: Steal::new(self.lint_buffer), }; ResolverOutputs { global_ctxt, ast_lowering } } @@ -2056,3 +2057,7 @@ impl Finalize { Finalize { node_id, path_span, root_span, report_private: true } } } + +pub fn provide(providers: &mut ty::query::Providers) { + providers.registered_tools = macros::registered_tools; +} diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index b38c11e8bb8d4..37153854f7e7f 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -8,7 +8,6 @@ use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment}; use rustc_ast::{self as ast, Inline, ItemKind, ModKind, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; -use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; use rustc_errors::{struct_span_err, Applicability}; @@ -20,11 +19,11 @@ use rustc_hir::def::{self, DefKind, NonMacroAttrKind}; use rustc_hir::def_id::{CrateNum, LocalDefId}; use rustc_middle::middle::stability; use rustc_middle::ty::RegisteredTools; +use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE}; use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES}; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::feature_err; -use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::hygiene::{self, ExpnData, ExpnKind, LocalExpnId}; use rustc_span::hygiene::{AstPass, MacroKind}; @@ -111,15 +110,17 @@ fn fast_print_path(path: &ast::Path) -> Symbol { } } -pub(crate) fn registered_tools(sess: &Session, attrs: &[ast::Attribute]) -> FxHashSet { - let mut registered_tools = FxHashSet::default(); - for attr in sess.filter_by_name(attrs, sym::register_tool) { +pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { + let mut registered_tools = RegisteredTools::default(); + let krate = tcx.crate_for_resolver(()).borrow(); + for attr in tcx.sess.filter_by_name(&krate.attrs, sym::register_tool) { for nested_meta in attr.meta_item_list().unwrap_or_default() { match nested_meta.ident() { Some(ident) => { if let Some(old_ident) = registered_tools.replace(ident) { let msg = format!("{} `{}` was already registered", "tool", ident); - sess.struct_span_err(ident.span, &msg) + tcx.sess + .struct_span_err(ident.span, &msg) .span_label(old_ident.span, "already registered here") .emit(); } @@ -127,7 +128,10 @@ pub(crate) fn registered_tools(sess: &Session, attrs: &[ast::Attribute]) -> FxHa None => { let msg = format!("`{}` only accepts identifiers", sym::register_tool); let span = nested_meta.span(); - sess.struct_span_err(span, &msg).span_label(span, "not an identifier").emit(); + tcx.sess + .struct_span_err(span, &msg) + .span_label(span, "not an identifier") + .emit(); } } }