diff --git a/Cargo.lock b/Cargo.lock index 2cc2e094e9f9c..003bc6adb0e88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3945,6 +3945,7 @@ dependencies = [ "rustc_hashes", "rustc_hir_id", "rustc_index", + "rustc_lint_defs", "rustc_macros", "rustc_serialize", "rustc_span", @@ -3962,7 +3963,6 @@ dependencies = [ "rustc_abi", "rustc_arena", "rustc_ast", - "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_feature", @@ -3970,6 +3970,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_infer", + "rustc_lint", "rustc_lint_defs", "rustc_macros", "rustc_middle", diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index a2a5f8ab14236..0d53ed9d97a54 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -14,18 +14,6 @@ attr_parsing_deprecated_item_suggestion = .help = add `#![feature(deprecated_suggestion)]` to the crate root .note = see #94785 for more details -attr_parsing_empty_attribute = - unused attribute - .suggestion = {$valid_without_list -> - [true] remove these parentheses - *[other] remove this attribute - } - .note = {$valid_without_list -> - [true] using `{$attr_path}` with an empty list is equivalent to not using a list at all - *[other] using `{$attr_path}` with an empty list has no effect - } - - attr_parsing_empty_confusables = expected at least one confusable name attr_parsing_empty_link_name = @@ -119,19 +107,9 @@ attr_parsing_invalid_repr_hint_no_value = attr_parsing_invalid_since = 'since' must be a Rust version number, such as "1.31.0" -attr_parsing_invalid_style = {$is_used_as_inner -> - [false] crate-level attribute should be an inner attribute: add an exclamation mark: `#![{$name}]` - *[other] the `#![{$name}]` attribute can only be used at the crate root - } - .note = This attribute does not have an `!`, which means it is applied to this {$target} - attr_parsing_invalid_target = `#[{$name}]` attribute cannot be used on {$target} .help = `#[{$name}]` can {$only}be applied to {$applied} .suggestion = remove the attribute -attr_parsing_invalid_target_lint = `#[{$name}]` attribute cannot be used on {$target} - .warn = {-attr_parsing_previously_accepted} - .help = `#[{$name}]` can {$only}be applied to {$applied} - .suggestion = remove the attribute attr_parsing_limit_invalid = `limit` must be a non-negative integer @@ -250,19 +228,10 @@ attr_parsing_unsupported_literal_generic = attr_parsing_unsupported_literal_suggestion = consider removing the prefix -attr_parsing_unused_duplicate = - unused attribute - .suggestion = remove this attribute - .note = attribute also specified here - .warn = {-attr_parsing_previously_accepted} - attr_parsing_unused_multiple = multiple `{$name}` attributes .suggestion = remove this attribute .note = attribute also specified here --attr_parsing_previously_accepted = - this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - attr_parsing_whole_archive_needs_static = linking modifier `whole-archive` is only compatible with `static` linking kind diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index eda272fb7f2b7..fba1a663c0575 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -3,6 +3,7 @@ // SingleAttributeParser which is what we have two of here. use rustc_hir::attrs::{AttributeKind, InlineAttr}; +use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use super::prelude::*; @@ -56,9 +57,7 @@ impl SingleAttributeParser for InlineParser { } } ArgParser::NameValue(_) => { - let suggestions = cx.suggestions(); - let span = cx.attr_span; - cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); + cx.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT); return None; } } diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 5a4a4e7599101..46fa8ee713438 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -2,6 +2,7 @@ use rustc_feature::Features; use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection}; use rustc_hir::attrs::*; use rustc_session::Session; +use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use rustc_session::parse::feature_err; use rustc_span::kw; use rustc_target::spec::{Arch, BinaryFormat}; @@ -71,9 +72,7 @@ impl CombineAttributeParser for LinkParser { // Specifically `#[link = "dl"]` is accepted with a FCW // For more information, see https://github.com/rust-lang/rust/pull/143193 ArgParser::NameValue(nv) if nv.value_as_str().is_some_and(|v| v == sym::dl) => { - let suggestions = cx.suggestions(); - let span = cx.attr_span; - cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); + cx.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT); return None; } _ => { diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 787003519e78b..d2fa1d440f407 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -1,5 +1,6 @@ use rustc_errors::DiagArgValue; use rustc_hir::attrs::MacroUseArgs; +use rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS; use super::prelude::*; use crate::session_diagnostics::IllFormedAttributeInputLint; @@ -152,23 +153,13 @@ impl SingleAttributeParser for MacroExportParser { ArgParser::NoArgs => false, ArgParser::List(list) => { let Some(l) = list.single() else { - let span = cx.attr_span; - let suggestions = cx.suggestions(); - cx.emit_lint( - AttributeLintKind::InvalidMacroExportArguments { suggestions }, - span, - ); + cx.warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS); return None; }; match l.meta_item().and_then(|i| i.path().word_sym()) { Some(sym::local_inner_macros) => true, _ => { - let span = cx.attr_span; - let suggestions = cx.suggestions(); - cx.emit_lint( - AttributeLintKind::InvalidMacroExportArguments { suggestions }, - span, - ); + cx.warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS); return None; } } diff --git a/compiler/rustc_attr_parsing/src/attributes/prelude.rs b/compiler/rustc_attr_parsing/src/attributes/prelude.rs index 980366b5c372f..65c408fa6358c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prelude.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prelude.rs @@ -4,8 +4,6 @@ pub(super) use rustc_feature::{AttributeTemplate, template}; #[doc(hidden)] pub(super) use rustc_hir::attrs::AttributeKind; #[doc(hidden)] -pub(super) use rustc_hir::lints::AttributeLintKind; -#[doc(hidden)] pub(super) use rustc_hir::{MethodKind, Target}; #[doc(hidden)] pub(super) use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 23ecc0bf7d29f..e0b006030758b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -1,3 +1,5 @@ +use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; + use super::prelude::*; pub(crate) struct IgnoreParser; @@ -20,20 +22,13 @@ impl SingleAttributeParser for IgnoreParser { ArgParser::NoArgs => None, ArgParser::NameValue(name_value) => { let Some(str_value) = name_value.value_as_str() else { - let suggestions = cx.suggestions(); - let span = cx.attr_span; - cx.emit_lint( - AttributeLintKind::IllFormedAttributeInput { suggestions }, - span, - ); + cx.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT); return None; }; Some(str_value) } ArgParser::List(_) => { - let suggestions = cx.suggestions(); - let span = cx.attr_span; - cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); + cx.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT); return None; } }, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index dcb7341b4b5ec..bc74eaad50bc4 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -11,6 +11,7 @@ use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId}; use rustc_session::Session; +use rustc_session::lint::{Lint, LintId}; use rustc_span::{ErrorGuaranteed, Span, Symbol}; use crate::AttributeParser; @@ -381,7 +382,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing /// must be delayed until after HIR is built. This method will take care of the details of /// that. - pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) { + pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) { if !matches!( self.stage.should_emit(), ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true } @@ -389,11 +390,12 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { return; } let id = self.target_id; - (self.emit_lint)(AttributeLint { id, span, kind: lint }); + (self.emit_lint)(AttributeLint { lint_id: LintId::of(lint), id, span, kind }); } pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) { self.emit_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, AttributeLintKind::UnusedDuplicate { this: unused_span, other: used_span, @@ -409,6 +411,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { unused_span: Span, ) { self.emit_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, AttributeLintKind::UnusedDuplicate { this: unused_span, other: used_span, @@ -632,14 +635,25 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { } pub(crate) fn warn_empty_attribute(&mut self, span: Span) { - let attr_path = self.attr_path.clone(); + let attr_path = self.attr_path.clone().to_string(); let valid_without_list = self.template.word; self.emit_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, AttributeLintKind::EmptyAttribute { first_span: span, attr_path, valid_without_list }, span, ); } + pub(crate) fn warn_ill_formed_attribute_input(&mut self, lint: &'static Lint) { + let suggestions = self.suggestions(); + let span = self.attr_span; + self.emit_lint( + lint, + AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None }, + span, + ); + } + pub(crate) fn suggestions(&self) -> Vec { let style = match self.parsed_description { // If the outer and inner spans are equal, we are parsing an embedded attribute diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 87e29b7b0de6e..b26a4a29cd2e2 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -8,6 +8,7 @@ use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::AttributeLint; use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target}; use rustc_session::Session; +use rustc_session::lint::BuiltinLintDiag; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage}; @@ -115,7 +116,12 @@ impl<'sess> AttributeParser<'sess, Early> { OmitDoc::Skip, std::convert::identity, |lint| { - crate::lints::emit_attribute_lint(&lint, sess); + sess.psess.buffer_lint( + lint.lint_id.lint, + lint.span, + lint.id, + BuiltinLintDiag::AttributeLint(lint.kind), + ) }, ) } @@ -183,8 +189,13 @@ impl<'sess> AttributeParser<'sess, Early> { sess, stage: Early { emit_errors }, }; - let mut emit_lint = |lint| { - crate::lints::emit_attribute_lint(&lint, sess); + let mut emit_lint = |lint: AttributeLint| { + sess.psess.buffer_lint( + lint.lint_id.lint, + lint.span, + lint.id, + BuiltinLintDiag::AttributeLint(lint.kind), + ) }; if let Some(safety) = attr_safety { parser.check_attribute_safety( diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 7a7f2555287a2..7cef70f88e1ca 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -97,7 +97,6 @@ mod interface; /// like lists or name-value pairs. pub mod parser; -mod lints; mod safety; mod session_diagnostics; mod target_checking; @@ -111,7 +110,6 @@ pub use attributes::cfg_select::*; pub use attributes::util::{is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version}; pub use context::{Early, Late, OmitDoc, ShouldEmit}; pub use interface::AttributeParser; -pub use lints::emit_attribute_lint; pub use session_diagnostics::ParsedDescription; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs deleted file mode 100644 index a23884d7f71eb..0000000000000 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ /dev/null @@ -1,114 +0,0 @@ -use std::borrow::Cow; - -use rustc_errors::{DiagArgValue, LintEmitter}; -use rustc_hir::Target; -use rustc_hir::lints::{AttributeLint, AttributeLintKind}; -use rustc_span::sym; - -use crate::session_diagnostics; - -pub fn emit_attribute_lint(lint: &AttributeLint, lint_emitter: L) { - let AttributeLint { id, span, kind } = lint; - - match kind { - &AttributeLintKind::UnusedDuplicate { this, other, warning } => lint_emitter - .emit_node_span_lint( - rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - *id, - *span, - session_diagnostics::UnusedDuplicate { this, other, warning }, - ), - AttributeLintKind::IllFormedAttributeInput { suggestions } => { - lint_emitter.emit_node_span_lint( - rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT, - *id, - *span, - session_diagnostics::IllFormedAttributeInput { - num_suggestions: suggestions.len(), - suggestions: DiagArgValue::StrListSepByAnd( - suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), - ), - }, - ); - } - AttributeLintKind::InvalidMacroExportArguments { suggestions } => lint_emitter - .emit_node_span_lint( - rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS, - *id, - *span, - session_diagnostics::IllFormedAttributeInput { - num_suggestions: suggestions.len(), - suggestions: DiagArgValue::StrListSepByAnd( - suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), - ), - }, - ), - AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => { - lint_emitter.emit_node_span_lint( - rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - *id, - *first_span, - session_diagnostics::EmptyAttributeList { - attr_span: *first_span, - attr_path: attr_path.clone(), - valid_without_list: *valid_without_list, - }, - ) - } - AttributeLintKind::InvalidTarget { name, target, applied, only } => lint_emitter - .emit_node_span_lint( - // This check is here because `deprecated` had its own lint group and removing this would be a breaking change - if name.segments[0].name == sym::deprecated - && ![ - Target::Closure, - Target::Expression, - Target::Statement, - Target::Arm, - Target::MacroCall, - ] - .contains(target) - { - rustc_session::lint::builtin::USELESS_DEPRECATED - } else { - rustc_session::lint::builtin::UNUSED_ATTRIBUTES - }, - *id, - *span, - session_diagnostics::InvalidTargetLint { - name: name.clone(), - target: target.plural_name(), - applied: DiagArgValue::StrListSepByAnd( - applied.into_iter().map(|i| Cow::Owned(i.to_string())).collect(), - ), - only, - attr_span: *span, - }, - ), - - &AttributeLintKind::InvalidStyle { ref name, is_used_as_inner, target, target_span } => { - lint_emitter.emit_node_span_lint( - rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - *id, - *span, - session_diagnostics::InvalidAttrStyle { - name: name.clone(), - is_used_as_inner, - target_span: (!is_used_as_inner).then_some(target_span), - target, - }, - ) - } - &AttributeLintKind::UnsafeAttrOutsideUnsafe { - attribute_name_span, - sugg_spans: (left, right), - } => lint_emitter.emit_node_span_lint( - rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE, - *id, - *span, - session_diagnostics::UnsafeAttrOutsideUnsafeLint { - span: attribute_name_span, - suggestion: session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion { left, right }, - }, - ), - } -} diff --git a/compiler/rustc_attr_parsing/src/safety.rs b/compiler/rustc_attr_parsing/src/safety.rs index ff385bf13aaa9..52baf2136173d 100644 --- a/compiler/rustc_attr_parsing/src/safety.rs +++ b/compiler/rustc_attr_parsing/src/safety.rs @@ -2,6 +2,8 @@ use rustc_ast::Safety; use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir::AttrPath; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; +use rustc_session::lint::LintId; +use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE; use rustc_span::{Span, sym}; use crate::context::Stage; @@ -74,6 +76,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { ); } else { emit_lint(AttributeLint { + lint_id: LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE), id: target_id, span: path_span, kind: AttributeLintKind::UnsafeAttrOutsideUnsafe { diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index f94f0867451f0..c4f6f9c6a38cb 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -6,8 +6,8 @@ use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, }; use rustc_feature::AttributeTemplate; -use rustc_hir::{AttrPath, Target}; -use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_hir::AttrPath; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; use crate::fluent_generated as fluent; @@ -417,25 +417,6 @@ pub(crate) struct UnusedMultiple { pub name: Symbol, } -#[derive(LintDiagnostic)] -#[diag(attr_parsing_unused_duplicate)] -pub(crate) struct UnusedDuplicate { - #[suggestion(code = "", applicability = "machine-applicable")] - pub this: Span, - #[note] - pub other: Span, - #[warning] - pub warning: bool, -} - -// FIXME(jdonszelmann): duplicated in rustc_lints, should be moved here completely. -#[derive(LintDiagnostic)] -#[diag(attr_parsing_ill_formed_attribute_input)] -pub(crate) struct IllFormedAttributeInput { - pub num_suggestions: usize, - pub suggestions: DiagArgValue, -} - #[derive(Diagnostic)] #[diag(attr_parsing_ill_formed_attribute_input)] pub(crate) struct IllFormedAttributeInputLint { @@ -501,29 +482,6 @@ pub(crate) struct EmptyConfusables { pub span: Span, } -#[derive(LintDiagnostic)] -#[diag(attr_parsing_empty_attribute)] -#[note] -pub(crate) struct EmptyAttributeList { - #[suggestion(code = "", applicability = "machine-applicable")] - pub attr_span: Span, - pub attr_path: AttrPath, - pub valid_without_list: bool, -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_invalid_target_lint)] -#[warning] -#[help] -pub(crate) struct InvalidTargetLint { - pub name: AttrPath, - pub target: &'static str, - pub applied: DiagArgValue, - pub only: &'static str, - #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] - pub attr_span: Span, -} - #[derive(Diagnostic)] #[help] #[diag(attr_parsing_invalid_target)] @@ -803,15 +761,6 @@ pub(crate) struct UnsafeAttrOutsideUnsafe { pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, } -#[derive(LintDiagnostic)] -#[diag(attr_parsing_unsafe_attr_outside_unsafe)] -pub(crate) struct UnsafeAttrOutsideUnsafeLint { - #[label] - pub span: Span, - #[subdiagnostic] - pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, -} - #[derive(Subdiagnostic)] #[multipart_suggestion( attr_parsing_unsafe_attr_outside_unsafe_suggestion, @@ -881,16 +830,6 @@ pub(crate) struct SuffixedLiteralInAttribute { pub span: Span, } -#[derive(LintDiagnostic)] -#[diag(attr_parsing_invalid_style)] -pub(crate) struct InvalidAttrStyle { - pub name: AttrPath, - pub is_used_as_inner: bool, - #[note] - pub target_span: Option, - pub target: Target, -} - #[derive(Diagnostic)] #[diag(attr_parsing_empty_link_name, code = E0454)] pub(crate) struct EmptyLinkName { diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index fabd364d3d7f8..88efb910c1601 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -5,6 +5,7 @@ use rustc_errors::DiagArgValue; use rustc_feature::Features; use rustc_hir::lints::AttributeLintKind; use rustc_hir::{MethodKind, Target}; +use rustc_span::sym; use crate::AttributeParser; use crate::context::{AcceptContext, Stage}; @@ -102,13 +103,31 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { let allowed_targets = allowed_targets.allowed_targets(); let (applied, only) = allowed_targets_applied(allowed_targets, target, cx.features); let name = cx.attr_path.clone(); + + let lint = if name.segments[0].name == sym::deprecated + && ![ + Target::Closure, + Target::Expression, + Target::Statement, + Target::Arm, + Target::MacroCall, + ] + .contains(&target) + { + rustc_session::lint::builtin::USELESS_DEPRECATED + } else { + rustc_session::lint::builtin::UNUSED_ATTRIBUTES + }; + let attr_span = cx.attr_span; cx.emit_lint( + lint, AttributeLintKind::InvalidTarget { - name, - target, + name: name.to_string(), + target: target.plural_name(), only: if only { "only " } else { "" }, applied, + attr_span, }, attr_span, ); @@ -145,15 +164,15 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { return; } - let lint = AttributeLintKind::InvalidStyle { - name: cx.attr_path.clone(), + let kind = AttributeLintKind::InvalidStyle { + name: cx.attr_path.to_string(), is_used_as_inner: cx.attr_style == AttrStyle::Inner, - target, + target: target.name(), target_span: cx.target_span, }; let attr_span = cx.attr_span; - cx.emit_lint(lint, attr_span); + cx.emit_lint(rustc_session::lint::builtin::UNUSED_ATTRIBUTES, kind, attr_span); } } diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index c57e0baea05f6..cd28677b6a8fd 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -11,6 +11,7 @@ use rustc_ast::{ use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; use rustc_hir::AttrPath; +use rustc_hir::lints::AttributeLintKind; use rustc_parse::parse_in; use rustc_session::errors::report_lit_error; use rustc_session::lint::BuiltinLintDiag; @@ -202,10 +203,10 @@ fn emit_malformed_attribute( ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, - BuiltinLintDiag::IllFormedAttributeInput { + BuiltinLintDiag::AttributeLint(AttributeLintKind::IllFormedAttributeInput { suggestions: suggestions.clone(), docs: template.docs, - }, + }), ); } else { suggestions.sort(); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 5a7a178582e34..12e6700e0b8d6 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -64,8 +64,8 @@ pub use rustc_error_messages::{ fallback_fluent_bundle, fluent_bundle, into_diag_arg_using_display, }; use rustc_hashes::Hash128; +use rustc_lint_defs::LintExpectationId; pub use rustc_lint_defs::{Applicability, listify, pluralize}; -use rustc_lint_defs::{Lint, LintExpectationId}; use rustc_macros::{Decodable, Encodable}; pub use rustc_span::ErrorGuaranteed; pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; @@ -106,20 +106,6 @@ rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24); #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24); -/// Used to avoid depending on `rustc_middle` in `rustc_attr_parsing`. -/// Always the `TyCtxt`. -pub trait LintEmitter: Copy { - type Id: Copy; - #[track_caller] - fn emit_node_span_lint( - self, - lint: &'static Lint, - hir_id: Self::Id, - span: impl Into, - decorator: impl for<'a> LintDiagnostic<'a, ()> + DynSend + 'static, - ); -} - #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)] pub enum SuggestionStyle { /// Hide the suggested code when displaying this suggestion inline. diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index 1008a3e787d01..13e73acf07375 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -16,6 +16,7 @@ rustc_error_messages = { path = "../rustc_error_messages" } rustc_hashes = { path = "../rustc_hashes" } rustc_hir_id = { path = "../rustc_hir_id" } rustc_index = { path = "../rustc_index" } +rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index a4c60fd2cc1ad..eba2d182d2c48 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -1,8 +1,10 @@ use rustc_data_structures::fingerprint::Fingerprint; +pub use rustc_lint_defs::AttributeLintKind; +use rustc_lint_defs::LintId; use rustc_macros::HashStable_Generic; use rustc_span::Span; -use crate::{AttrPath, HirId, Target}; +use crate::HirId; #[derive(Debug)] pub struct DelayedLints { @@ -24,46 +26,8 @@ pub enum DelayedLint { #[derive(Debug, HashStable_Generic)] pub struct AttributeLint { + pub lint_id: LintId, pub id: Id, pub span: Span, pub kind: AttributeLintKind, } - -#[derive(Debug, HashStable_Generic)] -pub enum AttributeLintKind { - /// Copy of `IllFormedAttributeInput` - /// specifically for the `invalid_macro_export_arguments` lint until that is removed, - /// see - InvalidMacroExportArguments { - suggestions: Vec, - }, - UnusedDuplicate { - this: Span, - other: Span, - warning: bool, - }, - IllFormedAttributeInput { - suggestions: Vec, - }, - EmptyAttribute { - first_span: Span, - attr_path: AttrPath, - valid_without_list: bool, - }, - InvalidTarget { - name: AttrPath, - target: Target, - applied: Vec, - only: &'static str, - }, - InvalidStyle { - name: AttrPath, - is_used_as_inner: bool, - target: Target, - target_span: Span, - }, - UnsafeAttrOutsideUnsafe { - attribute_name_span: Span, - sugg_spans: (Span, Span), - }, -} diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index e5017794d8f29..8d114862b3fe1 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -13,7 +13,6 @@ itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } @@ -21,6 +20,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } +rustc_lint = { path = "../rustc_lint" } rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 1d2a456b555e7..538fb8c7df1ea 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -158,7 +158,19 @@ pub fn provide(providers: &mut Providers) { fn emit_delayed_lint(lint: &DelayedLint, tcx: TyCtxt<'_>) { match lint { DelayedLint::AttributeParsing(attribute_lint) => { - rustc_attr_parsing::emit_attribute_lint(attribute_lint, tcx) + tcx.node_span_lint( + attribute_lint.lint_id.lint, + attribute_lint.id, + attribute_lint.span, + |diag| { + rustc_lint::decorate_attribute_lint( + tcx.sess, + Some(tcx), + &attribute_lint.kind, + diag, + ); + }, + ); } } } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 75e7af4c11733..1bcdda96e13a2 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -245,6 +245,19 @@ lint_dropping_copy_types = calls to `std::mem::drop` with a value that implement lint_dropping_references = calls to `std::mem::drop` with a reference instead of an owned value does nothing .label = argument has type `{$arg_ty}` +lint_empty_attribute = + unused attribute + .suggestion = {$valid_without_list -> + [true] remove these parentheses + *[other] remove this attribute + } + .note = {$valid_without_list -> + [true] using `{$attr_path}` with an empty list is equivalent to not using a list at all + *[other] using `{$attr_path}` with an empty list has no effect + } + +-lint_previously_accepted = + this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! lint_enum_intrinsics_mem_discriminant = the return value of `mem::discriminant` is unspecified when called with a non-enum type .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum @@ -458,6 +471,17 @@ lint_invalid_reference_casting_note_book = for more information, visit + [false] crate-level attribute should be an inner attribute: add an exclamation mark: `#![{$name}]` + *[other] the `#![{$name}]` attribute can only be used at the crate root + } + .note = This attribute does not have an `!`, which means it is applied to this {$target} + +lint_invalid_target = `#[{$name}]` attribute cannot be used on {$target} + .warn = {-lint_previously_accepted} + .help = `#[{$name}]` can {$only}be applied to {$applied} + .suggestion = remove the attribute + lint_lintpass_by_hand = implementing `LintPass` by hand .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead @@ -890,6 +914,10 @@ lint_unpredictable_fn_pointer_comparisons = function pointer comparisons do not lint_unqualified_local_imports = `use` of a local item without leading `self::`, `super::`, or `crate::` +lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe + .label = usage of unsafe attribute +lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)` + lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´ lint_untranslatable_diag = diagnostics should be created using translatable messages @@ -922,6 +950,12 @@ lint_unused_def = unused {$pre}`{$def}`{$post} that must be used lint_unused_delim = unnecessary {$delim} around {$item} .suggestion = remove these {$delim} +lint_unused_duplicate = + unused attribute + .suggestion = remove this attribute + .note = attribute also specified here + .warn = {-lint_previously_accepted} + lint_unused_import_braces = braces around {$node} is unnecessary lint_unused_imports = {$num_snippets -> diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 87ccd114ee97e..b654bc848ecfc 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -4,6 +4,7 @@ use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; use rustc_errors::{ Applicability, Diag, DiagArgValue, LintDiagnostic, elided_lifetime_in_path_suggestion, }; +use rustc_hir::lints::AttributeLintKind; use rustc_middle::middle::stability; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -301,7 +302,21 @@ pub fn decorate_builtin_lint( BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag) } - BuiltinLintDiag::IllFormedAttributeInput { suggestions, docs } => { + BuiltinLintDiag::AttributeLint(kind) => decorate_attribute_lint(sess, tcx, &kind, diag), + } +} + +pub fn decorate_attribute_lint( + _sess: &Session, + _tcx: Option>, + kind: &AttributeLintKind, + diag: &mut Diag<'_, ()>, +) { + match kind { + &AttributeLintKind::UnusedDuplicate { this, other, warning } => { + lints::UnusedDuplicate { this, other, warning }.decorate_lint(diag) + } + AttributeLintKind::IllFormedAttributeInput { suggestions, docs } => { lints::IllFormedAttributeInput { num_suggestions: suggestions.len(), suggestions: DiagArgValue::StrListSepByAnd( @@ -312,5 +327,42 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag) } + AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => { + lints::EmptyAttributeList { + attr_span: *first_span, + attr_path: attr_path.clone(), + valid_without_list: *valid_without_list, + } + .decorate_lint(diag) + } + AttributeLintKind::InvalidTarget { name, target, applied, only, attr_span } => { + lints::InvalidTargetLint { + name: name.clone(), + target, + applied: DiagArgValue::StrListSepByAnd( + applied.into_iter().map(|i| Cow::Owned(i.to_string())).collect(), + ), + only, + attr_span: *attr_span, + } + .decorate_lint(diag) + } + &AttributeLintKind::InvalidStyle { ref name, is_used_as_inner, target, target_span } => { + lints::InvalidAttrStyle { + name: name.clone(), + is_used_as_inner, + target_span: (!is_used_as_inner).then_some(target_span), + target, + } + .decorate_lint(diag) + } + &AttributeLintKind::UnsafeAttrOutsideUnsafe { + attribute_name_span, + sugg_spans: (left, right), + } => lints::UnsafeAttrOutsideUnsafeLint { + span: attribute_name_span, + suggestion: lints::UnsafeAttrOutsideUnsafeSuggestion { left, right }, + } + .decorate_lint(diag), } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 78b76e083d416..23afbf6c0d7b7 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -129,7 +129,7 @@ use unused::*; #[rustfmt::skip] pub use builtin::{MissingDoc, SoftLints}; pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore}; -pub use early::diagnostics::decorate_builtin_lint; +pub use early::diagnostics::{decorate_attribute_lint, decorate_builtin_lint}; pub use early::{EarlyCheckNode, check_ast_node}; pub use late::{check_crate, late_lint_mod, unerased_lint_store}; pub use levels::LintLevelsBuilder; diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 51708bc045830..4f28d503af3c3 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3126,3 +3126,68 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { } } } + +#[derive(LintDiagnostic)] +#[diag(lint_empty_attribute)] +#[note] +pub(crate) struct EmptyAttributeList { + #[suggestion(code = "", applicability = "machine-applicable")] + pub attr_span: Span, + pub attr_path: String, + pub valid_without_list: bool, +} + +#[derive(LintDiagnostic)] +#[diag(lint_invalid_target)] +#[warning] +#[help] +pub(crate) struct InvalidTargetLint { + pub name: String, + pub target: &'static str, + pub applied: DiagArgValue, + pub only: &'static str, + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] + pub attr_span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_invalid_style)] +pub(crate) struct InvalidAttrStyle { + pub name: String, + pub is_used_as_inner: bool, + #[note] + pub target_span: Option, + pub target: &'static str, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_duplicate)] +pub(crate) struct UnusedDuplicate { + #[suggestion(code = "", applicability = "machine-applicable")] + pub this: Span, + #[note] + pub other: Span, + #[warning] + pub warning: bool, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unsafe_attr_outside_unsafe)] +pub(crate) struct UnsafeAttrOutsideUnsafeLint { + #[label] + pub span: Span, + #[subdiagnostic] + pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + lint_unsafe_attr_outside_unsafe_suggestion, + applicability = "machine-applicable" +)] +pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion { + #[suggestion_part(code = "unsafe(")] + pub left: Span, + #[suggestion_part(code = ")")] + pub right: Span, +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index abdc41eb57c21..3c6e7d04a29dd 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -696,10 +696,42 @@ pub enum BuiltinLintDiag { extern_crate: Symbol, local_crate: Symbol, }, + AttributeLint(AttributeLintKind), +} + +#[derive(Debug, HashStable_Generic)] +pub enum AttributeLintKind { + UnusedDuplicate { + this: Span, + other: Span, + warning: bool, + }, IllFormedAttributeInput { suggestions: Vec, docs: Option<&'static str>, }, + EmptyAttribute { + first_span: Span, + attr_path: String, + valid_without_list: bool, + }, + InvalidTarget { + name: String, + target: &'static str, + applied: Vec, + only: &'static str, + attr_span: Span, + }, + InvalidStyle { + name: String, + is_used_as_inner: bool, + target: &'static str, + target_span: Span, + }, + UnsafeAttrOutsideUnsafe { + attribute_name_span: Span, + sugg_spans: (Span, Span), + }, } pub type RegisteredTools = FxIndexSet; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0cd36d5e971de..a16c2232c3a68 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -30,7 +30,7 @@ use rustc_data_structures::sync::{ self, DynSend, DynSync, FreezeReadGuard, Lock, RwLock, WorkerLocal, }; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, LintEmitter, MultiSpan, + Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan, }; use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; @@ -1534,20 +1534,6 @@ pub struct TyCtxt<'tcx> { gcx: &'tcx GlobalCtxt<'tcx>, } -impl<'tcx> LintEmitter for TyCtxt<'tcx> { - type Id = HirId; - - fn emit_node_span_lint( - self, - lint: &'static Lint, - hir_id: HirId, - span: impl Into, - decorator: impl for<'a> LintDiagnostic<'a, ()>, - ) { - self.emit_node_span_lint(lint, hir_id, span, decorator); - } -} - // Explicitly implement `DynSync` and `DynSend` for `TyCtxt` to short circuit trait resolution. Its // field are asserted to implement these traits below, so this is trivially safe, and it greatly // speeds-up compilation of this crate and its dependents. diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index e52475cdd5bde..acc65fc11a2a2 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -6,7 +6,6 @@ use std::sync::atomic::AtomicBool; use std::{env, io}; use rand::{RngCore, rng}; -use rustc_ast::NodeId; use rustc_data_structures::base_n::{CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; @@ -22,7 +21,7 @@ use rustc_errors::timings::TimingSectionHandler; use rustc_errors::translation::Translator; use rustc_errors::{ Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, Diagnostic, ErrorGuaranteed, FatalAbort, - LintEmitter, TerminalUrl, fallback_fluent_bundle, + TerminalUrl, fallback_fluent_bundle, }; use rustc_hir::limit::Limit; use rustc_macros::HashStable_Generic; @@ -160,20 +159,6 @@ pub struct Session { pub invocation_temp: Option, } -impl LintEmitter for &'_ Session { - type Id = NodeId; - - fn emit_node_span_lint( - self, - lint: &'static rustc_lint_defs::Lint, - node_id: Self::Id, - span: impl Into, - decorator: impl for<'a> rustc_errors::LintDiagnostic<'a, ()> + DynSend + 'static, - ) { - self.psess.buffer_lint(lint, span, node_id, decorator); - } -} - #[derive(Clone, Copy)] pub enum CodegenUnits { /// Specified by the user. In this case we try fairly hard to produce the