diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b8d708d42ff10..0abc84d6927d2 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -243,7 +243,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { attribute_parser: AttributeParser::new( tcx.sess, tcx.features(), - tcx.registered_tools(()), + tcx.registered_attribute_tools(()), ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }, ), delayed_lints: Vec::new(), diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 155df43c813e8..01367ebff9410 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -283,7 +283,7 @@ impl AttributeParser for NakedParser { let span = self.span?; - let Some(tools) = cx.tools else { + let Some(tools) = cx.attribute_tools else { unreachable!("tools required while parsing attributes"); }; diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index eb78bc0775f6b..e7c597366de9f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -317,12 +317,33 @@ impl CombineAttributeParser for FeatureParser { } } -pub(crate) struct RegisterToolParser; +pub(crate) struct RegisterAttributeTool; +pub(crate) struct RegisterLintTool; +pub(crate) struct RegisterTool; -impl CombineAttributeParser for RegisterToolParser { - const PATH: &[Symbol] = &[sym::register_tool]; +pub(crate) trait RegisterToolKind: 'static { + const SYMBOL: Symbol; +} + +impl RegisterToolKind for RegisterAttributeTool { + const SYMBOL: Symbol = sym::register_attribute_tool; +} + +impl RegisterToolKind for RegisterLintTool { + const SYMBOL: Symbol = sym::register_lint_tool; +} + +impl RegisterToolKind for RegisterTool { + const SYMBOL: Symbol = sym::register_tool; +} + +pub(crate) struct RegisterToolParser(Kind); + +impl CombineAttributeParser for RegisterToolParser { + const PATH: &[Symbol] = &[K::SYMBOL]; type Item = Ident; - const CONVERT: ConvertFn = |tools, _span| AttributeKind::RegisterTool(tools); + const CONVERT: ConvertFn = + |tools, _span| AttributeKind::RegisterTool { kind: K::SYMBOL, tools }; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!(List: &["tool1, tool2, ..."]); const STABILITY: AttributeStability = unstable!(register_tool); diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index fb5ca0375900a..8e3fa6c1d099c 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -165,7 +165,9 @@ attribute_parsers!( Combine, Combine, Combine, - Combine, + Combine>, + Combine>, + Combine>, Combine, Combine, Combine, diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index e8bef70be550a..89be1c75b563d 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -37,7 +37,7 @@ pub struct EmitAttribute( /// Context created once, for example as part of the ast lowering /// context, through which all attributes can be lowered. pub struct AttributeParser<'sess> { - pub(crate) tools: Option<&'sess RegisteredTools>, + pub(crate) attribute_tools: Option<&'sess RegisteredTools>, pub(crate) features: Option<&'sess Features>, pub(crate) sess: &'sess Session, pub(crate) should_emit: ShouldEmit, @@ -45,7 +45,7 @@ pub struct AttributeParser<'sess> { /// *Only* parse attributes with this symbol. /// /// Used in cases where we want the lowering infrastructure for parse just a single attribute. - parse_only: Option<&'static [Symbol]>, + parse_only: Option<&'sess [Symbol]>, } impl<'sess> AttributeParser<'sess> { @@ -68,7 +68,7 @@ impl<'sess> AttributeParser<'sess> { pub fn parse_limited( sess: &'sess Session, attrs: &[ast::Attribute], - sym: &'static [Symbol], + sym: &'sess [Symbol], ) -> Option { Self::parse_limited_should_emit( sess, @@ -90,7 +90,7 @@ impl<'sess> AttributeParser<'sess> { pub fn parse_limited_should_emit( sess: &'sess Session, attrs: &[ast::Attribute], - sym: &'static [Symbol], + sym: &'sess [Symbol], target_span: Span, target_node_id: NodeId, target: Target, @@ -122,15 +122,15 @@ impl<'sess> AttributeParser<'sess> { pub fn parse_limited_all( sess: &'sess Session, attrs: &[ast::Attribute], - parse_only: Option<&'static [Symbol]>, + parse_only: Option<&'sess [Symbol]>, target: Target, target_span: Span, target_node_id: NodeId, features: Option<&'sess Features>, should_emit: ShouldEmit, - tools: Option<&'sess RegisteredTools>, + attribute_tools: Option<&'sess RegisteredTools>, ) -> Vec { - let mut p = Self { features, tools, parse_only, sess, should_emit }; + let mut p = Self { features, attribute_tools, parse_only, sess, should_emit }; p.parse_attribute_list( attrs, target_span, @@ -212,7 +212,8 @@ impl<'sess> AttributeParser<'sess> { parse_fn: fn(cx: &mut AcceptContext<'_, '_>, item: &I) -> T, template: &AttributeTemplate, ) -> T { - let mut parser = Self { features, tools: None, parse_only: None, sess, should_emit }; + let mut parser = + Self { features, attribute_tools: None, parse_only: None, sess, should_emit }; let mut emit_lint = |lint_id: LintId, span: MultiSpan, kind: EmitAttribute| { sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0) }; @@ -252,10 +253,16 @@ impl<'sess> AttributeParser<'sess> { pub fn new( sess: &'sess Session, features: &'sess Features, - tools: &'sess RegisteredTools, + attribute_tools: &'sess RegisteredTools, should_emit: ShouldEmit, ) -> Self { - Self { features: Some(features), tools: Some(tools), parse_only: None, sess, should_emit } + Self { + features: Some(features), + attribute_tools: Some(attribute_tools), + parse_only: None, + sess, + should_emit, + } } pub(crate) fn sess(&self) -> &'sess Session { diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 31353d1eac0fb..97bfd42c54e35 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -59,7 +59,7 @@ use rustc_session::lint::{Lint, LintId}; use rustc_session::output::invalid_output_for_target; use rustc_session::{EarlyDiagCtxt, Session, config}; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::{DUMMY_SP, FileName}; +use rustc_span::{DUMMY_SP, FileName, sym}; use rustc_target::json::ToJson; use rustc_target::spec::{Target, TargetTuple}; use tracing::trace; @@ -713,13 +713,18 @@ fn print_crate_info( let crate_name = passes::get_crate_name(sess, attrs); let lint_store = crate::unerased_lint_store(sess); let features = rustc_expand::config::features(sess, attrs, crate_name); - let registered_tools = rustc_resolve::registered_tools_ast(sess.dcx(), attrs, sess); + let registered_lint_tools = rustc_resolve::registered_tools_ast( + sess.dcx(), + attrs, + sess, + sym::register_lint_tool, + ); let builder = rustc_lint::LintLevelsBuilder::crate_root( sess, &features, true, lint_store, - ®istered_tools, + ®istered_lint_tools, attrs, ); for lint in lint_store.get_lints() { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 30a77811bb389..db156d31ff07e 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1161,8 +1161,11 @@ pub trait ResolverExpand { cfg_span: Span, ); - /// Tools registered with `#![register_tool]` and used by tool attributes and lints. - fn registered_tools(&self) -> &RegisteredTools; + /// Tools registered with `#![register_tool]` or `#![register_attribute_tool]`. + fn registered_attribute_tools(&self) -> &RegisteredTools; + + /// Tools registered with `#![register_tool]` or `#![register_lint_tool]`. + fn registered_lint_tools(&self) -> &RegisteredTools; /// Mark this invocation id as a glob delegation. fn register_glob_delegation(&mut self, invoc_id: LocalExpnId); @@ -1189,7 +1192,7 @@ pub trait LintStoreExpand { &self, sess: &Session, features: &Features, - registered_tools: &RegisteredTools, + registered_lint_tools: &RegisteredTools, node_id: NodeId, attrs: &[Attribute], items: &[Box], diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 0fd21e017ff61..f5aedd9e05d8c 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1407,7 +1407,7 @@ impl InvocationCollectorNode for Box { lint_store.pre_expansion_lint( ecx.sess, ecx.ecfg.features, - ecx.resolver.registered_tools(), + ecx.resolver.registered_lint_tools(), ecx.current_expansion.lint_node_id, &attrs, &items, @@ -2268,7 +2268,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { self.cx.current_expansion.lint_node_id, Some(self.cx.ecfg.features), ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }, - Some(self.cx.resolver.registered_tools()), + Some(self.cx.resolver.registered_attribute_tools()), ); let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span }; diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 2e13b7705c9d9..6810380d58aa6 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -184,6 +184,8 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[ sym::ffi_pure, sym::ffi_const, + sym::register_attribute_tool, + sym::register_lint_tool, sym::register_tool, // `#[cfi_encoding = ""]` sym::cfi_encoding, diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index ab24b0ed37d22..b5fac5988b69b 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -95,7 +95,7 @@ declare_features! ( (removed, crate_visibility_modifier, "1.63.0", Some(53120), Some("removed in favor of `pub(crate)`"), 97254), /// Allows using custom attributes (RFC 572). (removed, custom_attribute, "1.0.0", Some(29642), - Some("removed in favor of `#![register_tool]` and `#![register_attr]`"), 66070), + Some("removed in favor of `#![register_tool]`"), 66070), /// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. (removed, custom_derive, "1.32.0", Some(29644), Some("subsumed by `#[proc_macro_derive]`")), diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index e419c63162f7a..aaffc6f8f2e79 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1266,7 +1266,10 @@ pub enum AttributeKind { ReexportTestHarnessMain(Symbol), /// Represents `#[register_tool]` - RegisterTool(ThinVec), + RegisterTool { + kind: Symbol, + tools: ThinVec, + }, /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr { diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index fb6d7e4549fae..99f20ca6701e3 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -96,7 +96,7 @@ impl AttributeKind { ProfilerRuntime => No, RecursionLimit { .. } => No, ReexportTestHarnessMain(..) => No, - RegisterTool(..) => No, + RegisterTool { .. } => No, Repr { .. } => No, RustcAbi { .. } => No, RustcAlign { .. } => No, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index b230fe3be68e3..172cd6edbc868 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -88,7 +88,7 @@ fn pre_expansion_lint<'a>( sess: &Session, features: &Features, lint_store: &LintStore, - registered_tools: &RegisteredTools, + registered_lint_tools: &RegisteredTools, check_node: impl EarlyCheckNode<'a>, node_name: Symbol, ) { @@ -99,7 +99,7 @@ fn pre_expansion_lint<'a>( features, true, lint_store, - registered_tools, + registered_lint_tools, None, rustc_lint::BuiltinCombinedPreExpansionLintPass::new(), check_node, @@ -116,13 +116,20 @@ impl LintStoreExpand for LintStoreExpandImpl<'_> { &self, sess: &Session, features: &Features, - registered_tools: &RegisteredTools, + registered_lint_tools: &RegisteredTools, node_id: ast::NodeId, attrs: &[ast::Attribute], items: &[Box], name: Symbol, ) { - pre_expansion_lint(sess, features, self.0, registered_tools, (node_id, attrs, items), name); + pre_expansion_lint( + sess, + features, + self.0, + registered_lint_tools, + (node_id, attrs, items), + name, + ); } } @@ -146,7 +153,7 @@ fn configure_and_expand( sess, features, lint_store, - tcx.registered_tools(()), + tcx.registered_lint_tools(()), lint_check_node, crate_name, ); @@ -477,7 +484,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { tcx.features(), false, lint_store, - tcx.registered_tools(()), + tcx.registered_lint_tools(()), Some(lint_buffer), rustc_lint::BuiltinCombinedEarlyLintPass::new(), (&*krate, &*krate.attrs), @@ -794,7 +801,8 @@ fn resolver_for_lowering_raw<'tcx>( &'tcx ty::ResolverGlobalCtxt, ) { let arenas = Resolver::arenas(); - let _ = tcx.registered_tools(()); // Uses `crate_for_resolver`. + let _ = tcx.registered_attribute_tools(()); // Uses `crate_for_resolver`. + let _ = tcx.registered_lint_tools(()); // Uses `crate_for_resolver`. let (krate, pre_configured_attrs) = tcx.crate_for_resolver(()).steal(); let mut resolver = Resolver::new( tcx, diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 4ea1a3f1209e4..a83cb8ef937b6 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -347,13 +347,13 @@ impl LintStore { &self, lint_name: &str, tool_name: Option, - registered_tools: &RegisteredTools, + registered_lint_tools: &RegisteredTools, ) -> CheckLintNameResult<'_> { if let Some(tool_name) = tool_name { // FIXME: rustc and rustdoc are considered tools for lints, but not for attributes. if tool_name != sym::rustc && tool_name != sym::rustdoc - && !registered_tools.contains(&Ident::with_dummy_span(tool_name)) + && !registered_lint_tools.contains(&Ident::with_dummy_span(tool_name)) { return CheckLintNameResult::NoTool; } @@ -573,7 +573,7 @@ impl<'a> EarlyContext<'a> { features: &'a Features, lint_added_lints: bool, lint_store: &'a LintStore, - registered_tools: &'a RegisteredTools, + registered_lint_tools: &'a RegisteredTools, buffered: LintBuffer, ) -> EarlyContext<'a> { EarlyContext { @@ -582,7 +582,7 @@ impl<'a> EarlyContext<'a> { features, lint_added_lints, lint_store, - registered_tools, + registered_lint_tools, ), buffered, } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index df6683c14df42..be87b81b636a5 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -314,7 +314,7 @@ pub fn check_ast_node<'a>( features: &Features, pre_expansion: bool, lint_store: &LintStore, - registered_tools: &RegisteredTools, + registered_lint_tools: &RegisteredTools, lint_buffer: Option, builtin_lints: impl EarlyLintPass + 'static, check_node: impl EarlyCheckNode<'a>, @@ -324,7 +324,7 @@ pub fn check_ast_node<'a>( features, !pre_expansion, lint_store, - registered_tools, + registered_lint_tools, lint_buffer.unwrap_or_default(), ); diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index b7c24b9f2d5b5..dc560280b6d28 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -171,7 +171,7 @@ fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLe }, lint_added_lints: false, store, - registered_tools: tcx.registered_tools(()), + registered_lint_tools: tcx.registered_lint_tools(()), }; if owner == hir::CRATE_OWNER_ID { @@ -389,7 +389,7 @@ pub struct LintLevelsBuilder<'s, P> { provider: P, lint_added_lints: bool, store: &'s LintStore, - registered_tools: &'s RegisteredTools, + registered_lint_tools: &'s RegisteredTools, } pub(crate) struct BuilderPush { @@ -402,7 +402,7 @@ impl<'s> LintLevelsBuilder<'s, TopDown> { features: &'s Features, lint_added_lints: bool, store: &'s LintStore, - registered_tools: &'s RegisteredTools, + registered_lint_tools: &'s RegisteredTools, ) -> Self { let mut builder = LintLevelsBuilder { sess, @@ -410,7 +410,7 @@ impl<'s> LintLevelsBuilder<'s, TopDown> { provider: TopDown { sets: LintLevelSets::new(), cur: COMMAND_LINE }, lint_added_lints, store, - registered_tools, + registered_lint_tools, }; builder.process_command_line(); assert_eq!(builder.provider.sets.list.len(), 1); @@ -422,10 +422,10 @@ impl<'s> LintLevelsBuilder<'s, TopDown> { features: &'s Features, lint_added_lints: bool, store: &'s LintStore, - registered_tools: &'s RegisteredTools, + registered_lint_tools: &'s RegisteredTools, crate_attrs: &[ast::Attribute], ) -> Self { - let mut builder = Self::new(sess, features, lint_added_lints, store, registered_tools); + let mut builder = Self::new(sess, features, lint_added_lints, store, registered_lint_tools); builder.add(crate_attrs, true); builder } @@ -503,7 +503,8 @@ where .dcx() .emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() }); } - match self.store.check_lint_name(lint_name_only, tool_name, self.registered_tools) { + match self.store.check_lint_name(lint_name_only, tool_name, self.registered_lint_tools) + { CheckLintNameResult::Renamed(ref replace) => { let name = lint_name.as_str(); let suggestion = RenamedLintSuggestion::WithoutSpan { replace }; @@ -768,7 +769,7 @@ where let tool_name = tool_ident.map(|ident| ident.name); let name = pprust::path_to_string(&meta_item.path); let lint_result = - self.store.check_lint_name(&name, tool_name, self.registered_tools); + self.store.check_lint_name(&name, tool_name, self.registered_lint_tools); let (ids, name) = match lint_result { CheckLintNameResult::Ok(ids) => { @@ -837,7 +838,7 @@ where // NOTE: `new_name` already includes the tool name, so we don't // have to add it again. let CheckLintNameResult::Ok(ids) = - self.store.check_lint_name(replace, None, self.registered_tools) + self.store.check_lint_name(replace, None, self.registered_lint_tools) else { panic!("renamed lint does not exist: {replace}"); }; diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index c01ff3d5d0561..d2818b19ea837 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -150,10 +150,16 @@ rustc_queries! { desc { "triggering a delayed bug for testing incremental" } } - /// Collects the list of all tools registered using `#![register_tool]`. - query registered_tools(_: ()) -> &'tcx ty::RegisteredTools { + /// Collects the list of all tools registered using `#![register_tool]` or `#![register_attribute_tool]`. + query registered_attribute_tools(_: ()) -> &'tcx ty::RegisteredTools { arena_cache - desc { "compute registered tools for crate" } + desc { "compute registered attribute tools for crate" } + } + + /// Collects the list of all tools registered using `#![register_tool]` or `#![register_lint_tool]`. + query registered_lint_tools(_: ()) -> &'tcx ty::RegisteredTools { + arena_cache + desc { "compute registered lint tools for crate" } } query early_lint_checks(_: ()) { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 01c31d6acb9dd..ad6004e093940 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -313,7 +313,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::ProfilerRuntime => (), AttributeKind::RecursionLimit { .. } => (), AttributeKind::ReexportTestHarnessMain(..) => (), - AttributeKind::RegisterTool(..) => (), + AttributeKind::RegisterTool { .. } => (), // handled below this loop and elsewhere AttributeKind::Repr { .. } => (), AttributeKind::RustcAbi { .. } => (), diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index cdc2df5bf2945..0f8181c92c7f3 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -187,7 +187,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { let mut parser = AttributeParser::new( &self.r.tcx.sess, self.r.tcx.features(), - self.r.tcx().registered_tools(()), + self.r.tcx().registered_attribute_tools(()), ShouldEmit::Nothing, ); let attrs = parser.parse_attribute_list( diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 2baf423e296d6..91c1e7f016bbe 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1216,13 +1216,19 @@ pub(crate) struct CannotFindBuiltinMacroWithName { } #[derive(Diagnostic)] -#[diag("tool `{$tool}` was already registered")] -pub(crate) struct ToolWasAlreadyRegistered { +#[diag("tool `{$tool}` is predefined and cannot be registered")] +pub(crate) struct ToolPredefined { + #[primary_span] + pub(crate) span: Span, + pub(crate) tool: Ident, +} + +#[derive(Diagnostic)] +#[diag("tool `{$tool}` is reserved and cannot be registered")] +pub(crate) struct ToolReserved { #[primary_span] pub(crate) span: Span, pub(crate) tool: Ident, - #[label("already registered here")] - pub(crate) old_ident_span: Span, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_resolve/src/error_helper.rs b/compiler/rustc_resolve/src/error_helper.rs index 3f62f3b2df3bd..11d52c9d2bd09 100644 --- a/compiler/rustc_resolve/src/error_helper.rs +++ b/compiler/rustc_resolve/src/error_helper.rs @@ -1334,10 +1334,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { })); } Scope::ExternPreludeFlags => {} - Scope::ToolPrelude => { + Scope::ToolAttributePrelude => { let res = Res::NonMacroAttr(NonMacroAttrKind::Tool); suggestions.extend( - this.registered_tools + this.registered_attribute_tools .iter() .map(|ident| TypoSuggestion::new(ident.name, ident.span, res)), ); diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 2e69405811db4..a427020f023b7 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -156,7 +156,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::ExternPreludeItems | Scope::ExternPreludeFlags => { use_prelude || module_and_extern_prelude || extern_prelude } - Scope::ToolPrelude => use_prelude, + Scope::ToolAttributePrelude => use_prelude, Scope::StdLibPrelude => use_prelude || ns == MacroNS, Scope::BuiltinTypes => true, }; @@ -222,8 +222,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::BuiltinAttrs => break, // nowhere else to search Scope::ExternPreludeItems => Scope::ExternPreludeFlags, Scope::ExternPreludeFlags if module_and_extern_prelude || extern_prelude => break, - Scope::ExternPreludeFlags => Scope::ToolPrelude, - Scope::ToolPrelude => Scope::StdLibPrelude, + Scope::ExternPreludeFlags => Scope::ToolAttributePrelude, + Scope::ToolAttributePrelude => Scope::StdLibPrelude, Scope::StdLibPrelude => match ns { TypeNS => Scope::BuiltinTypes, ValueNS => break, // nowhere else to search @@ -720,7 +720,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => Err(Determinacy::Determined), } } - Scope::ToolPrelude => match self.registered_tool_decls.get(&ident) { + Scope::ToolAttributePrelude => match self.registered_attribute_tool_decls.get(&ident) { Some(decl) => Ok(*decl), None => Err(Determinacy::Determined), }, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index c7b4686fcd234..b9568a113f5d9 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -132,8 +132,8 @@ enum Scope<'ra> { ExternPreludeItems, /// Extern prelude names introduced by `--extern` flags. ExternPreludeFlags, - /// Tool modules introduced with `#![register_tool]`. - ToolPrelude, + /// Tool modules introduced with `#![register_tool]` or `#![register_attribute_tool]`. + ToolAttributePrelude, /// Standard library prelude introduced with an internal `#[prelude_import]` import. StdLibPrelude, /// Built-in types. @@ -1423,10 +1423,11 @@ pub struct Resolver<'ra, 'tcx> { dummy_decl: Decl<'ra>, builtin_type_decls: FxHashMap>, builtin_attr_decls: FxHashMap>, - registered_tool_decls: FxHashMap>, + registered_attribute_tool_decls: FxHashMap>, macro_names: FxHashSet = default::fx_hash_set(), builtin_macros: FxHashMap = default::fx_hash_map(), - registered_tools: &'tcx RegisteredTools, + registered_attribute_tools: &'tcx RegisteredTools, + registered_lint_tools: &'tcx RegisteredTools, macro_use_prelude: FxIndexMap>, /// Eagerly populated map of all local macro definitions. local_macro_map: FxHashMap> = default::fx_hash_map(), @@ -1802,7 +1803,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT); let extern_prelude = build_extern_prelude(tcx, attrs); - let registered_tools = tcx.registered_tools(()); + let registered_attribute_tools = tcx.registered_attribute_tools(()); + let registered_lint_tools = tcx.registered_lint_tools(()); let edition = tcx.sess.edition(); let mut resolver = Resolver { @@ -1840,7 +1842,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { (*builtin_attr, decl) }) .collect(), - registered_tool_decls: registered_tools + registered_attribute_tool_decls: registered_attribute_tools .iter() .map(|&ident| { let res = Res::ToolMod; @@ -1848,7 +1850,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { (IdentKey::new(ident), decl) }) .collect(), - registered_tools, + registered_attribute_tools, + registered_lint_tools, macro_use_prelude: Default::default(), extern_macro_map: Default::default(), dummy_ext_bang: arenas.alloc_macro(SyntaxExtension::dummy_bang(edition)), @@ -2123,7 +2126,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Scope::ExternPreludeItems | Scope::ExternPreludeFlags - | Scope::ToolPrelude + | Scope::ToolAttributePrelude | Scope::BuiltinTypes => {} _ => unreachable!(), } @@ -2808,7 +2811,10 @@ impl Finalize { } pub fn provide(providers: &mut Providers) { - providers.registered_tools = macros::registered_tools; + providers.registered_attribute_tools = + |tcx, ()| macros::registered_tools(tcx, sym::register_attribute_tool); + providers.registered_lint_tools = + |tcx, ()| macros::registered_tools(tcx, sym::register_lint_tool); } /// A wrapper around `&mut Resolver` that may be mutable or immutable, depending on a conditions. diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index fade23f9cf308..8ae0cd60d973c 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -121,37 +121,50 @@ fn fast_print_path(path: &ast::Path) -> Symbol { } } -pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { +pub(crate) fn registered_tools(tcx: TyCtxt<'_>, sym: Symbol) -> RegisteredTools { let (_, pre_configured_attrs) = &*tcx.crate_for_resolver(()).borrow(); - registered_tools_ast(tcx.dcx(), pre_configured_attrs, tcx.sess) + registered_tools_ast(tcx.dcx(), pre_configured_attrs, tcx.sess, sym) } pub fn registered_tools_ast( dcx: DiagCtxtHandle<'_>, pre_configured_attrs: &[ast::Attribute], sess: &Session, + sym: Symbol, ) -> RegisteredTools { let mut registered_tools = RegisteredTools::default(); - if let Some(Attribute::Parsed(AttributeKind::RegisterTool(tools))) = + if let Some(Attribute::Parsed(AttributeKind::RegisterTool { kind: _, tools })) = + AttributeParser::parse_limited(sess, pre_configured_attrs, &[sym]) + { + registered_tools.extend(tools); + } + + if let Some(Attribute::Parsed(AttributeKind::RegisterTool { kind: _, tools })) = AttributeParser::parse_limited(sess, pre_configured_attrs, &[sym::register_tool]) { - for tool in tools { - if let Some(old_tool) = registered_tools.replace(tool) { - dcx.emit_err(diagnostics::ToolWasAlreadyRegistered { - span: tool.span, - tool, - old_ident_span: old_tool.span, - }); - } - } + registered_tools.extend(tools); + } + + // `rustc` is reserved and is an error if registered. + // Tools with `rustc` prefix is reserved but is not an error if registered. + let rustc = Ident::with_dummy_span(sym::rustc); + if let Some((_, tool)) = registered_tools.shift_remove_full(&rustc) { + dcx.emit_err(diagnostics::ToolReserved { span: tool.span, tool }); } // We implicitly add `rustfmt`, `clippy`, `diagnostic`, `miri` and `rust_analyzer` to known - // tools, but it's not an error to register them explicitly. + // tools. let predefined_tools = [sym::clippy, sym::rustfmt, sym::diagnostic, sym::miri, sym::rust_analyzer]; - registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span)); + + for sym in predefined_tools { + let tool = Ident::with_dummy_span(sym); + if let Some(old_tool) = registered_tools.replace(tool) { + dcx.emit_err(diagnostics::ToolPredefined { span: old_tool.span, tool: old_tool }); + } + } + registered_tools } @@ -518,8 +531,12 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { }); } - fn registered_tools(&self) -> &RegisteredTools { - self.registered_tools + fn registered_attribute_tools(&self) -> &RegisteredTools { + self.registered_attribute_tools + } + + fn registered_lint_tools(&self) -> &RegisteredTools { + self.registered_lint_tools } fn register_glob_delegation(&mut self, invoc_id: LocalExpnId) { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 72990de7e58aa..aaf436686ecd7 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1677,6 +1677,8 @@ symbols! { reg_ptr, reg_upper, register_attr, + register_attribute_tool, + register_lint_tool, register_tool, relaxed_adts, relaxed_struct_unsize, diff --git a/tests/ui/tool-attributes/cfg-register.rs b/tests/ui/tool-attributes/cfg-register.rs new file mode 100644 index 0000000000000..c835e6bd54740 --- /dev/null +++ b/tests/ui/tool-attributes/cfg-register.rs @@ -0,0 +1,12 @@ +//@ check-pass +// +//@revisions: tool split_attr_lint + +#![feature(register_tool)] +#![cfg_attr(tool, register_tool(foo, bar))] +#![cfg_attr(split_attr_lint, register_attribute_tool(foo))] +#![cfg_attr(split_attr_lint, register_lint_tool(bar))] + +#[foo::a] +#[allow(bar::b)] +fn main() {} diff --git a/tests/ui/tool-attributes/duplicate-tool.rs b/tests/ui/tool-attributes/duplicate-tool.rs new file mode 100644 index 0000000000000..603292d1eb3cd --- /dev/null +++ b/tests/ui/tool-attributes/duplicate-tool.rs @@ -0,0 +1,15 @@ +//@ check-pass +#![feature(register_tool)] +// Register a tool multiple times is okay. +#![register_tool(foo)] +#![register_tool(foo)] +#![register_tool(bar)] +#![register_attribute_tool(bar)] +#![register_tool(baz)] +#![register_lint_tool(baz)] +#![register_attribute_tool(qux)] +#![register_attribute_tool(qux)] +#![register_lint_tool(quux)] +#![register_lint_tool(quux)] + +fn main() {} diff --git a/tests/ui/tool-attributes/predefined-tool.rs b/tests/ui/tool-attributes/predefined-tool.rs new file mode 100644 index 0000000000000..fa69cb3bbf83b --- /dev/null +++ b/tests/ui/tool-attributes/predefined-tool.rs @@ -0,0 +1,13 @@ +#![feature(register_tool)] +// Register predefined tool or "rustc" is error. +#![register_tool(clippy)] //~ ERROR predefined + //~^ ERROR predefined +#![register_attribute_tool(miri)] //~ ERROR predefined +#![register_lint_tool(rustfmt)] //~ ERROR predefined +#![register_tool(diagnostic)] //~ ERROR predefined + //~^ ERROR predefined +#![register_attribute_tool(rust_analyzer)] //~ ERROR predefined +#![register_tool(rustc)] //~ ERROR reserved + //~^ ERROR reserved + +fn main() {} diff --git a/tests/ui/tool-attributes/predefined-tool.stderr b/tests/ui/tool-attributes/predefined-tool.stderr new file mode 100644 index 0000000000000..d318c8d047e44 --- /dev/null +++ b/tests/ui/tool-attributes/predefined-tool.stderr @@ -0,0 +1,62 @@ +error: tool `rustc` is reserved and cannot be registered + --> $DIR/predefined-tool.rs:10:18 + | +LL | #![register_tool(rustc)] + | ^^^^^ + +error: tool `clippy` is predefined and cannot be registered + --> $DIR/predefined-tool.rs:3:18 + | +LL | #![register_tool(clippy)] + | ^^^^^^ + +error: tool `diagnostic` is predefined and cannot be registered + --> $DIR/predefined-tool.rs:7:18 + | +LL | #![register_tool(diagnostic)] + | ^^^^^^^^^^ + +error: tool `miri` is predefined and cannot be registered + --> $DIR/predefined-tool.rs:5:28 + | +LL | #![register_attribute_tool(miri)] + | ^^^^ + +error: tool `rust_analyzer` is predefined and cannot be registered + --> $DIR/predefined-tool.rs:9:28 + | +LL | #![register_attribute_tool(rust_analyzer)] + | ^^^^^^^^^^^^^ + +error: tool `rustc` is reserved and cannot be registered + --> $DIR/predefined-tool.rs:10:18 + | +LL | #![register_tool(rustc)] + | ^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: tool `clippy` is predefined and cannot be registered + --> $DIR/predefined-tool.rs:3:18 + | +LL | #![register_tool(clippy)] + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: tool `rustfmt` is predefined and cannot be registered + --> $DIR/predefined-tool.rs:6:23 + | +LL | #![register_lint_tool(rustfmt)] + | ^^^^^^^ + +error: tool `diagnostic` is predefined and cannot be registered + --> $DIR/predefined-tool.rs:7:18 + | +LL | #![register_tool(diagnostic)] + | ^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 9 previous errors +