diff --git a/Cargo.lock b/Cargo.lock index 36213a1e4e481..aae429e2ef255 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4331,6 +4331,7 @@ dependencies = [ "rustc_apfloat", "rustc_ast", "rustc_ast_pretty", + "rustc_attr_ir", "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", @@ -4478,6 +4479,7 @@ dependencies = [ "rustc_apfloat", "rustc_arena", "rustc_ast", + "rustc_attr_ir", "rustc_data_structures", "rustc_errors", "rustc_hir", diff --git a/compiler/rustc_attr_ir/src/data_structures.rs b/compiler/rustc_attr_ir/src/data_structures.rs index d722d515582dc..607eb74c14012 100644 --- a/compiler/rustc_attr_ir/src/data_structures.rs +++ b/compiler/rustc_attr_ir/src/data_structures.rs @@ -24,6 +24,7 @@ use thin_vec::ThinVec; pub use crate::canonical_symbols::{CanonicalSymbol, CanonicalSymbols}; use crate::diagnostic::*; use crate::lang_items::LangItem; +use crate::lint::LintCheck; use crate::pretty_printing::PrintAttribute; use crate::stability::{DefaultBodyStability, PartialConstStability, Stability}; @@ -933,6 +934,9 @@ pub enum AttributeKind { /// Represents `#[linkage]`. Linkage(Linkage, Span), + /// Represents `#[allow]`, `#[warn]`, `#[deny]`, `#[forbid]`, and `#[expect]`. + LintCheck(ThinVec), + /// Represents `#[loop_match]`. LoopMatch(Span), diff --git a/compiler/rustc_attr_ir/src/encode_cross_crate.rs b/compiler/rustc_attr_ir/src/encode_cross_crate.rs index 6f05f763f2ada..e06d5646e6ae1 100644 --- a/compiler/rustc_attr_ir/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_ir/src/encode_cross_crate.rs @@ -58,6 +58,7 @@ impl AttributeKind { LinkOrdinal { .. } => No, LinkSection { .. } => Yes, // Needed for rustdoc Linkage(..) => No, + LintCheck(..) => No, LoopMatch(..) => No, MacroEscape => No, MacroExport { .. } => Yes, diff --git a/compiler/rustc_attr_ir/src/lib.rs b/compiler/rustc_attr_ir/src/lib.rs index f835e257762a9..79bd690cbbc4c 100644 --- a/compiler/rustc_attr_ir/src/lib.rs +++ b/compiler/rustc_attr_ir/src/lib.rs @@ -29,6 +29,7 @@ pub mod diagnostic; pub mod diagnostic_items; mod encode_cross_crate; pub mod lang_items; +pub mod lint; mod pretty_printing; mod stability; pub mod target; diff --git a/compiler/rustc_attr_ir/src/lint.rs b/compiler/rustc_attr_ir/src/lint.rs new file mode 100644 index 0000000000000..3783115ae8db4 --- /dev/null +++ b/compiler/rustc_attr_ir/src/lint.rs @@ -0,0 +1,38 @@ +use rustc_macros::{Decodable, Encodable, PrintAttribute, StableHash}; +use rustc_span::{Span, Symbol, sym}; +use thin_vec::ThinVec; + +use crate::{HashIgnoredAttrId, PrintAttribute}; +#[derive(Clone, Copy, Debug, StableHash, Encodable, Decodable, PrintAttribute)] +pub enum LintCheckKind { + Allow, + Warn, + Deny, + Forbid, + Expect, +} + +impl LintCheckKind { + pub fn sym(self) -> Symbol { + match self { + LintCheckKind::Allow => sym::allow, + LintCheckKind::Warn => sym::warn, + LintCheckKind::Deny => sym::deny, + LintCheckKind::Forbid => sym::forbid, + LintCheckKind::Expect => sym::expect, + } + } +} + +#[derive(Clone, Debug, StableHash, Encodable, Decodable, PrintAttribute)] +pub struct LintCheck { + pub name: ThinVec, + pub span: Span, + pub attr_index: u16, + pub lint_index: u16, + pub kind: LintCheckKind, + pub reason: Option, + /// Needed by `LintExpectationId` to track fulfilled expectations + pub attr_id: HashIgnoredAttrId, + pub attr_span: Span, +} diff --git a/compiler/rustc_attr_ir/src/pretty_printing.rs b/compiler/rustc_attr_ir/src/pretty_printing.rs index cd8a0c0e1e96f..5a8fb506c6f7b 100644 --- a/compiler/rustc_attr_ir/src/pretty_printing.rs +++ b/compiler/rustc_attr_ir/src/pretty_printing.rs @@ -17,6 +17,8 @@ use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; use rustc_structures::{CollapseMacroDebuginfo, CrateType, Limit, NativeLibKind, SanitizerSet}; use thin_vec::ThinVec; +use crate::HashIgnoredAttrId; + /// This trait is used to print attributes in `rustc_hir_pretty`. /// /// For structs and enums it can be derived using [`rustc_macros::PrintAttribute`]. @@ -189,7 +191,7 @@ macro_rules! print_tup { } print_tup!(A B C D E F G H); -print_skip!(Span, (), ErrorGuaranteed, AttrId); +print_skip!(Span, (), ErrorGuaranteed, AttrId, HashIgnoredAttrId); print_disp!(u8, u16, u32, u128, usize, bool, NonZero, Limit); print_debug!( Symbol, diff --git a/compiler/rustc_attr_parsing/src/attributes/lint.rs b/compiler/rustc_attr_parsing/src/attributes/lint.rs new file mode 100644 index 0000000000000..6a121c3de8147 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/lint.rs @@ -0,0 +1,196 @@ +use rustc_attr_ir::AttributeKind; +use rustc_attr_ir::lint::{LintCheck, LintCheckKind}; +use rustc_attr_ir::target::{AssocCtxt, GenericParamKind, MethodKind, Target}; +use rustc_lint_defs::builtin::UNUSED_ATTRIBUTES; +use rustc_span::{Span, Symbol, sym}; +use thin_vec::ThinVec; + +use crate::attributes::{AcceptMapping, AttributeParser, AttributeStability}; +use crate::context::{AcceptContext, ExpectStringLiteral, FinalizeContext}; +use crate::parser::ArgParser; +use crate::target_checking::AllowedTargets; +use crate::target_checking::Policy::{Allow, Warn}; +use crate::{AttributeTemplate, diagnostics, template}; + +const LINT_TEMPLATE: AttributeTemplate = template!( + List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#], + "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes" +); + +#[derive(Default, Debug)] +pub(crate) struct LintParser { + attr_index: u16, + lints: ThinVec, +} + +impl LintParser { + fn parse(&mut self, kind: LintCheckKind, cx: &mut AcceptContext<'_, '_>, args: &ArgParser) { + let attr_index = self.attr_index; + let attr_span = cx.attr_span; + let attr_id = cx.attr_id.expect("no `AttrId` for lint attribute"); + let mut lints: Vec<(ThinVec, Span)> = Vec::new(); + + if let Some(list) = cx.expect_list(args, cx.attr_span) { + let mut parsers = list.sub_parsers(); + // Optionally, the last (and only the last) + // element can be `reason = "reason"` + let reason = try { + let p = parsers.last()?.meta_item()?; + let nv = p.args().as_name_value()?; + if !p.path().word_is(sym::reason) { + cx.emit_err(diagnostics::MalformedAttribute { + span: p.span(), + sub: diagnostics::MalformedAttributeSub::BadAttributeArgument(p.span()), + }); + } else { + parsers = &parsers[..(parsers.len() - 1)]; + } + + let reason = nv.expect_string_literal(cx)?; + reason + }; + + for item in parsers { + if let Some(p) = item.meta_item() { + match p.args() { + ArgParser::NoArgs => { + lints.push((p.path().segments().map(|i| i.name).collect(), p.span())) + } + // We're found a `reason = "reason"` but we're not the last element. + ArgParser::NameValue(nv) if p.path().word_is(sym::reason) => { + cx.emit_err(diagnostics::MalformedAttribute { + span: p.span(), + sub: diagnostics::MalformedAttributeSub::ReasonMustComeLast( + item.span(), + ), + }); + nv.expect_string_literal(cx); + } + ArgParser::NameValue(_) | ArgParser::List(_) => { + cx.emit_err(diagnostics::MalformedAttribute { + span: p.span(), + sub: diagnostics::MalformedAttributeSub::BadAttributeArgument( + item.span(), + ), + }); + } + } + } else { + cx.emit_err(diagnostics::MalformedAttribute { + span: item.span(), + sub: diagnostics::MalformedAttributeSub::BadAttributeArgument(item.span()), + }); + } + } + if parsers.is_empty() { + cx.emit_lint( + UNUSED_ATTRIBUTES, + diagnostics::Unused { + attr_span, + note: if list.is_empty() { + diagnostics::UnusedNote::EmptyList { name: kind.sym() } + } else { + diagnostics::UnusedNote::NoLints { name: kind.sym() } + }, + }, + attr_span, + ); + } + + for (lint_index, (name, span)) in lints.into_iter().enumerate() { + self.lints.push(LintCheck { + name, + span, + lint_index: lint_index as u16, + attr_index, + kind, + attr_id, + reason, + attr_span, + }) + } + } + + self.attr_index += 1 + } +} + +impl AttributeParser for LintParser { + const ATTRIBUTES: AcceptMapping = &[ + (&[sym::allow], LINT_TEMPLATE, AttributeStability::Stable, |this, cx, args| { + this.parse(LintCheckKind::Allow, cx, args) + }), + (&[sym::warn], LINT_TEMPLATE, AttributeStability::Stable, |this, cx, args| { + this.parse(LintCheckKind::Warn, cx, args) + }), + (&[sym::deny], LINT_TEMPLATE, AttributeStability::Stable, |this, cx, args| { + this.parse(LintCheckKind::Deny, cx, args) + }), + (&[sym::forbid], LINT_TEMPLATE, AttributeStability::Stable, |this, cx, args| { + this.parse(LintCheckKind::Forbid, cx, args) + }), + (&[sym::expect], LINT_TEMPLATE, AttributeStability::Stable, |this, cx, args| { + this.parse(LintCheckKind::Expect, cx, args) + }), + ]; + const ALLOWED_TARGETS: AllowedTargets<'_> = { + AllowedTargets::AllowList(&[ + Allow(Target::ExternCrate), + Allow(Target::Use), + Allow(Target::Static), + Allow(Target::Const), + Allow(Target::Fn), + Allow(Target::Closure), + Allow(Target::Mod), + Allow(Target::ForeignMod), + Allow(Target::GlobalAsm), + Allow(Target::TyAlias), + Allow(Target::Enum), + Allow(Target::Variant), + Allow(Target::Struct), + Allow(Target::Field), + Allow(Target::Union), + Allow(Target::Trait), + Allow(Target::TraitAlias), + Allow(Target::Impl { of_trait: false }), + Allow(Target::Impl { of_trait: true }), + Allow(Target::Expression), + Allow(Target::Statement), + Allow(Target::Arm), + Allow(Target::AssocConst(AssocCtxt::Impl { of_trait: false })), + Allow(Target::AssocConst(AssocCtxt::Trait)), + Allow(Target::AssocConst(AssocCtxt::Impl { of_trait: true })), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: false })), + Allow(Target::AssocTy(AssocCtxt::Trait)), + Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: true })), + Allow(Target::ForeignFn), + Allow(Target::ForeignStatic), + Allow(Target::ForeignTy), + Allow(Target::MacroDef), + Allow(Target::Param), + Allow(Target::PatField), + Allow(Target::ExprField), + Allow(Target::Crate), + Allow(Target::Delegation { mac: false }), + Allow(Target::Delegation { mac: true }), + Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: false }), + Allow(Target::GenericParam { kind: GenericParamKind::Lifetime, has_default: false }), + Allow(Target::GenericParam { kind: GenericParamKind::Const, has_default: false }), + Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: true }), + Allow(Target::GenericParam { kind: GenericParamKind::Lifetime, has_default: true }), + Allow(Target::GenericParam { kind: GenericParamKind::Const, has_default: true }), + Allow(Target::Loop), + Allow(Target::ForLoop), + Allow(Target::While), + Allow(Target::Break), + Warn(Target::MacroCall), + ]) + }; + fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option { + if self.lints.is_empty() { None } else { Some(AttributeKind::LintCheck(self.lints)) } + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 242b4a73b06a6..ca7c11de669b2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -52,6 +52,7 @@ pub(crate) mod dummy; pub(crate) mod inline; pub(crate) mod instruction_set; pub(crate) mod link_attrs; +pub(crate) mod lint; pub(crate) mod lint_helpers; pub(crate) mod loop_match; pub(crate) mod macro_attrs; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index f936f5aab8265..0179c2fc15010 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -10,7 +10,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use rustc_ast::{AttrStyle, MetaItemLit, Safety}; use rustc_attr_ir::target::Target; -use rustc_attr_ir::{AttrPath, Attribute, AttributeKind}; +use rustc_attr_ir::{AttrPath, Attribute, AttributeKind, HashIgnoredAttrId}; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan}; use rustc_feature::AttributeStability; @@ -43,6 +43,7 @@ use crate::attributes::dummy::*; use crate::attributes::inline::*; use crate::attributes::instruction_set::*; use crate::attributes::link_attrs::*; +use crate::attributes::lint::*; use crate::attributes::lint_helpers::*; use crate::attributes::loop_match::*; use crate::attributes::macro_attrs::*; @@ -166,6 +167,7 @@ attribute_parsers!( ConfusablesParser, ConstStabilityParser, DocParser, + LintParser, MacroUseParser, NakedParser, OnConstParser, @@ -387,6 +389,8 @@ pub struct AcceptContext<'f, 'sess> { /// Whether it is an inner or outer attribute. pub(crate) attr_style: AttrStyle, + pub(crate) attr_id: Option, + /// A description of the thing we are parsing using this attribute parser. /// We are not only using these parsers for attributes, but also for macros such as the `cfg!()` macro. pub(crate) parsed_description: ParsedDescription, diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index e5f49690f71dc..e7e965923dd61 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -2056,3 +2056,37 @@ pub(crate) struct UnusedDuplicate { )] pub warning: bool, } + +#[derive(Diagnostic)] +#[diag("malformed lint attribute input", code = E0452)] +pub(crate) struct MalformedAttribute { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sub: MalformedAttributeSub, +} + +#[derive(Subdiagnostic)] +pub(crate) enum MalformedAttributeSub { + #[label("bad attribute argument")] + BadAttributeArgument(#[primary_span] Span), + #[label("reason in lint attribute must come last")] + ReasonMustComeLast(#[primary_span] Span), +} + +#[derive(Subdiagnostic)] +pub(crate) enum UnusedNote { + #[note("attribute `{$name}` with an empty list has no effect")] + EmptyList { name: Symbol }, + #[note("attribute `{$name}` without any lints has no effect")] + NoLints { name: Symbol }, +} + +#[derive(Diagnostic)] +#[diag("unused attribute")] +pub(crate) struct Unused { + #[suggestion("remove this attribute", code = "", applicability = "machine-applicable")] + pub attr_span: Span, + #[subdiagnostic] + pub note: UnusedNote, +} diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 1cecce8fd43ef..1595aaf45cbb1 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -266,6 +266,7 @@ impl<'sess> AttributeParser<'sess> { attr_path, #[cfg(debug_assertions)] has_target_been_checked: false, + attr_id: None, }; parse_fn(&mut cx, args) } @@ -440,6 +441,7 @@ impl<'sess> AttributeParser<'sess> { attr_path: attr_path.clone(), #[cfg(debug_assertions)] has_target_been_checked: false, + attr_id: Some(HashIgnoredAttrId { attr_id: attr.id }), }; (accept.accept_fn)(&mut cx, &args); diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 8efe5bf4f1f90..cf2b96f4110d6 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -792,4 +792,8 @@ impl MetaItemListParser { let mut iter = self.mixed(); iter.next().filter(|_| iter.next().is_none()) } + + pub fn sub_parsers(&self) -> &[MetaItemOrLitParser] { + &self.sub_parsers + } } diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index a672f242449e4..0024d8b26f1fb 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -10,6 +10,7 @@ rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr_ir = { path = "../rustc_attr_ir" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_lint/src/diagnostics.rs b/compiler/rustc_lint/src/diagnostics.rs index d96cadaca87eb..697de0fbca163 100644 --- a/compiler/rustc_lint/src/diagnostics.rs +++ b/compiler/rustc_lint/src/diagnostics.rs @@ -62,25 +62,6 @@ impl Subdiagnostic for OverruledAttributeSub { } } -#[derive(Diagnostic)] -#[diag("malformed lint attribute input", code = E0452)] -pub(crate) struct MalformedAttribute { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub sub: MalformedAttributeSub, -} - -#[derive(Subdiagnostic)] -pub(crate) enum MalformedAttributeSub { - #[label("bad attribute argument")] - BadAttributeArgument(#[primary_span] Span), - #[label("reason must be a string literal")] - ReasonMustBeStringLiteral(#[primary_span] Span), - #[label("reason in lint attribute must come last")] - ReasonMustComeLast(#[primary_span] Span), -} - #[derive(Diagnostic)] #[diag("unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`", code = E0710)] pub(crate) struct UnknownToolInScopedLint { diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index 02184ac623908..d8998f028988e 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -1,3 +1,4 @@ +use rustc_attr_ir::find_attr; use rustc_data_structures::fx::FxHashSet; use rustc_lint_defs::builtin::UNFULFILLED_LINT_EXPECTATIONS; use rustc_lint_defs::{LintExpectationId, StableLintExpectationId}; @@ -35,7 +36,14 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option) { LintExpectationId::Unstable(id) => (id.attr_id, id.lint_index), LintExpectationId::Stable(id) => { // We are an `eval_always` query, so looking at the attribute's `AttrId` is ok. - (tcx.hir_attrs(id.hir_id)[id.attr_index as usize].id(), id.lint_index) + + let lint_checks = find_attr!(tcx, id.hir_id, LintCheck(lints) => lints).unwrap(); + let attr_id = lint_checks + .iter() + .find_map(|l| (l.attr_index == id.attr_index).then_some(l.attr_id.attr_id)) + .unwrap(); + + (attr_id, id.lint_index) } }; (attr_id, lint_index) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 472835388620c..b6b7da718408b 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -2,7 +2,11 @@ use std::fmt::Debug; use rustc_ast as ast; use rustc_ast::attr::AttributeExt; -use rustc_ast_pretty::pprust; +use rustc_ast::{CRATE_NODE_ID, join_path_syms}; +use rustc_attr_ir::lint::{LintCheck, LintCheckKind}; +use rustc_attr_ir::target::Target; +use rustc_attr_ir::{Attribute, AttributeKind, find_attr}; +use rustc_attr_parsing::{AttributeParser, Recovery, ShouldEmit}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordSet; use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, MultiSpan, msg}; @@ -33,10 +37,10 @@ use crate::builtin::MISSING_DOCS; use crate::context::{CheckLintNameResult, LintStore}; use crate::diagnostics::{ CheckNameUnknownTool, DeprecatedLintName, DeprecatedLintNameFromCommandLine, - IgnoredUnlessCrateSpecified, MalformedAttribute, MalformedAttributeSub, OverruledAttribute, - OverruledAttributeLint, OverruledAttributeSub, RemovedLint, RemovedLintFromCommandLine, - RenamedLint, RenamedLintFromCommandLine, RenamedLintSuggestion, RequestedLevel, UnknownLint, - UnknownLintFromCommandLine, UnknownLintSuggestion, UnknownToolInScopedLint, UnsupportedGroup, + IgnoredUnlessCrateSpecified, OverruledAttribute, OverruledAttributeLint, OverruledAttributeSub, + RemovedLint, RemovedLintFromCommandLine, RenamedLint, RenamedLintFromCommandLine, + RenamedLintSuggestion, RequestedLevel, UnknownLint, UnknownLintFromCommandLine, + UnknownLintSuggestion, UnknownToolInScopedLint, UnsupportedGroup, }; use crate::late::unerased_lint_store; @@ -229,7 +233,7 @@ pub trait LintLevelsProvider { fn mk_lint_expectation_id( &self, attr_id: AttrId, - attr_index: usize, + attr_index: u16, lint_index: u16, ) -> Self::LintExpectationId; } @@ -254,7 +258,7 @@ impl LintLevelsProvider for TopDown { fn mk_lint_expectation_id( &self, attr_id: AttrId, - _attr_index: usize, + _attr_index: u16, lint_index: u16, ) -> Self::LintExpectationId { UnstableLintExpectationId { attr_id, lint_index } @@ -292,10 +296,9 @@ impl LintLevelsProvider for LintLevelQueryMap<'_> { fn mk_lint_expectation_id( &self, _attr_id: AttrId, - attr_index: usize, + attr_index: u16, lint_index: u16, ) -> Self::LintExpectationId { - let attr_index = attr_index.try_into().unwrap(); StableLintExpectationId { hir_id: self.cur, attr_index, lint_index } } } @@ -665,9 +668,80 @@ where }; } - fn add(&mut self, attrs: &[impl AttributeExt], is_crate_node: bool) { - let sess = self.sess; - for (attr_index, attr) in attrs.iter().enumerate() { + fn parse_lint_attributes(&mut self, attrs: &[A]) -> Vec { + use std::any::{Any, TypeId}; + + for attr in attrs { + if let Some(attr_ir_attr) = ::downcast_ref::(attr) { + if let Attribute::Parsed(AttributeKind::LintCheck(lints)) = attr_ir_attr { + return lints.clone().into(); + } + } + } + + if TypeId::of::() == TypeId::of::() { + return Vec::new(); + } + + fn cast<'a, A: AttributeExt + 'static>(attrs: &'a [A]) -> &'a [ast::Attribute] { + if TypeId::of::() == TypeId::of::() { + unsafe { + core::slice::from_raw_parts( + attrs.as_ptr().cast::(), + attrs.len(), + ) + } + } else { + unreachable!("unknown implementor of `AttributeExt` {}", std::any::type_name::()) + } + } + + let parsed = AttributeParser::parse_limited_all( + self.sess, + cast(attrs), + Some(&|attr| { + // This is ...complicated. Sometimes we need to parse lint check + // attributes pre-expansion, but of course things are allowed to + // be invalid if they're removed by a macro/cfg attribute before + // we do attribute parsing, which happens (mostly) post-expansion. + // + // Unfortunately we're somewhat inconsistent - sometimes we just + // give up and sometimes we error. Take for example: + // + // #[expect] // OK + // #[expect[wut]] // OK + // #[expect(expect)] // OK + // #[expect(expect(expect))] //~ ERROR malformed lint attribute input + // #[deny(({!}))] // OK + // #[expect[helix::]] // OK + // #[cfg(false)] + // const _: () = (); + // + // FIXME: just allow everything? + let can_parse_pre_expansion = attr.meta_item_list().is_some(); + (attr.path_matches(&[sym::allow]) + || attr.path_matches(&[sym::warn]) + || attr.path_matches(&[sym::deny]) + || attr.path_matches(&[sym::forbid]) + || attr.path_matches(&[sym::expect])) + && can_parse_pre_expansion + }), + Target::Crate, + DUMMY_SP, + CRATE_NODE_ID, + Some(self.features), + ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }, + Some(self.registered_lint_tools), + ); + if let Some(lints) = find_attr!(&parsed, LintCheck(lints) => lints) { + return lints.clone().into(); + } + + Vec::new() + } + + fn add(&mut self, attrs: &[impl AttributeExt + 'static], is_crate_node: bool) { + for attr in attrs { if attr.is_automatically_derived_attr() { self.provider.insert( LintId::of(SINGLE_USE_LIFETIMES), @@ -684,230 +758,174 @@ where ); continue; } + } + let lint_checks = self.parse_lint_attributes(attrs); - let level = match Level::from_opt_symbol(attr.name()) { - None => continue, - Some(level) => level, - }; - - let Some(mut metas) = attr.meta_item_list() else { continue }; + let sess = self.sess; - // Check whether `metas` is empty, and get its last element. - let Some(tail_li) = metas.last() else { - // This emits the unused_attributes lint for `#[level()]` - continue; + for lint_check in lint_checks { + let LintCheck { + mut name, + span: sp, + attr_index, + lint_index, + kind, + reason, + attr_id, + attr_span: _, + } = lint_check; + + let level = match kind { + LintCheckKind::Allow => Level::Allow, + LintCheckKind::Warn => Level::Warn, + LintCheckKind::Deny => Level::Deny, + LintCheckKind::Forbid => Level::Forbid, + LintCheckKind::Expect => Level::Expect, }; - // Before processing the lint names, look for a reason (RFC 2383) - // at the end. - let mut reason = None; - if let Some(item) = tail_li.meta_item() { - match item.kind { - ast::MetaItemKind::Word => {} // actual lint names handled later - ast::MetaItemKind::NameValue(ref name_value) => { - if item.path == sym::reason { - if let ast::LitKind::Str(rationale, _) = name_value.kind { - reason = Some(rationale); - } else { - sess.dcx().emit_err(MalformedAttribute { - span: name_value.span, - sub: MalformedAttributeSub::ReasonMustBeStringLiteral( - name_value.span, - ), - }); - } - // found reason, reslice meta list to exclude it - metas.pop().unwrap(); - } else { - sess.dcx().emit_err(MalformedAttribute { - span: item.span, - sub: MalformedAttributeSub::BadAttributeArgument(item.span), - }); - } - } - ast::MetaItemKind::List(_) => { - sess.dcx().emit_err(MalformedAttribute { - span: item.span, - sub: MalformedAttributeSub::BadAttributeArgument(item.span), - }); - } - } - } - - for (lint_index, li) in metas.iter_mut().enumerate() { - // `Expect` is the only lint level with a `LintExpectationId` that can be created - // from an attribute. - let lint_id = (level == Level::Expect).then(|| { - self.provider.mk_lint_expectation_id(attr.id(), attr_index, lint_index as u16) - }); - - let sp = li.span(); - let meta_item = match li { - ast::MetaItemInner::MetaItem(meta_item) if meta_item.is_word() => meta_item, - _ => { - let sub = if let Some(item) = li.meta_item() - && let ast::MetaItemKind::NameValue(_) = item.kind - && item.path == sym::reason - { - MalformedAttributeSub::ReasonMustComeLast(sp) - } else { - MalformedAttributeSub::BadAttributeArgument(sp) - }; - - sess.dcx().emit_err(MalformedAttribute { span: sp, sub }); - continue; - } - }; - let tool_ident = if meta_item.path.segments.len() > 1 { - Some(meta_item.path.segments.remove(0).ident) - } else { - None - }; - 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_lint_tools); - - let (ids, name) = match lint_result { - CheckLintNameResult::Ok(ids) => { - let name = - meta_item.path.segments.last().expect("empty lint name").ident.name; - (ids, name) - } + // `Expect` is the only lint level with a `LintExpectationId` that can be created + // from an attribute. + let lint_id = (level == Level::Expect).then(|| { + self.provider.mk_lint_expectation_id(attr_id.attr_id, attr_index, lint_index) + }); - CheckLintNameResult::Tool(ids, new_lint_name) => { - let name = match new_lint_name { - None => { - let complete_name = - &format!("{}::{}", tool_ident.unwrap().name, name); - Symbol::intern(complete_name) - } - Some(new_lint_name) => { - self.emit_span_lint( - builtin::RENAMED_AND_REMOVED_LINTS, - sp.into(), - DeprecatedLintName { - name, - suggestion: sp, - replace: &new_lint_name, - }, - ); - Symbol::intern(&new_lint_name) - } - }; - (ids, name) - } + let tool_name = if name.len() > 1 { Some(name.remove(0)) } else { None }; - CheckLintNameResult::MissingTool => { - // If `MissingTool` is returned, then either the lint does not - // exist in the tool or the code was not compiled with the tool and - // therefore the lint was never added to the `LintStore`. To detect - // this is the responsibility of the lint tool. - continue; - } + let lint_name = join_path_syms(&name); + let lint_result = + self.store.check_lint_name(&lint_name, tool_name, self.registered_lint_tools); - CheckLintNameResult::NoTool => { - sess.dcx().emit_err(UnknownToolInScopedLint { - span: tool_ident.map(|ident| ident.span), - tool_name: tool_name.unwrap(), - lint_name: pprust::path_to_string(&meta_item.path), - is_nightly_build: sess.is_nightly_build(), - }); - continue; - } + let (ids, name) = match lint_result { + CheckLintNameResult::Ok(ids) => { + let name = name.last().expect("empty lint name"); + (ids, *name) + } - CheckLintNameResult::Renamed(ref replace) => { - if self.lint_added_lints { - let suggestion = - RenamedLintSuggestion::WithSpan { suggestion: sp, replace }; - let name = - tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name); + CheckLintNameResult::Tool(ids, new_lint_name) => { + let name = match new_lint_name { + None => { + let complete_name = &format!("{}::{}", tool_name.unwrap(), lint_name); + Symbol::intern(complete_name) + } + Some(new_lint_name) => { self.emit_span_lint( - RENAMED_AND_REMOVED_LINTS, + builtin::RENAMED_AND_REMOVED_LINTS, sp.into(), - RenamedLint { name: name.as_str(), replace, suggestion }, + DeprecatedLintName { + name: lint_name, + suggestion: sp, + replace: &new_lint_name, + }, ); + Symbol::intern(&new_lint_name) } + }; + (ids, name) + } - // If this lint was renamed, apply the new lint instead of ignoring the - // attribute. Ignore any errors or warnings that happen because the new - // name is inaccurate. - // 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_lint_tools) - else { - panic!("renamed lint does not exist: {replace}"); - }; - - (ids, Symbol::intern(&replace)) - } + CheckLintNameResult::MissingTool => { + // If `MissingTool` is returned, then either the lint does not + // exist in the tool or the code was not compiled with the tool and + // therefore the lint was never added to the `LintStore`. To detect + // this is the responsibility of the lint tool. + continue; + } - CheckLintNameResult::Removed(ref reason) => { - if self.lint_added_lints { - let name = - tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name); - self.emit_span_lint( - RENAMED_AND_REMOVED_LINTS, - sp.into(), - RemovedLint { name: name.as_str(), reason }, - ); - } - continue; + CheckLintNameResult::NoTool => { + sess.dcx().emit_err(UnknownToolInScopedLint { + span: Some(sp), + tool_name: tool_name.unwrap(), + lint_name, + is_nightly_build: sess.is_nightly_build(), + }); + continue; + } + + CheckLintNameResult::Renamed(ref replace) => { + if self.lint_added_lints { + let suggestion = + RenamedLintSuggestion::WithSpan { suggestion: sp, replace }; + let name = tool_name + .map(|tool| format!("{tool}::{lint_name}")) + .unwrap_or(lint_name); + self.emit_span_lint( + RENAMED_AND_REMOVED_LINTS, + sp.into(), + RenamedLint { name: name.as_str(), replace, suggestion }, + ); } - CheckLintNameResult::NoLint(suggestion) => { - if self.lint_added_lints { - let name = - tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name); - let suggestion = suggestion.map(|(replace, from_rustc)| { - UnknownLintSuggestion::WithSpan { - suggestion: sp, - replace, - from_rustc, - } - }); - self.emit_span_lint( - UNKNOWN_LINTS, - sp.into(), - UnknownLint { name, suggestion }, - ); - } - continue; + // If this lint was renamed, apply the new lint instead of ignoring the + // attribute. Ignore any errors or warnings that happen because the new + // name is inaccurate. + // 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_lint_tools) + else { + panic!("renamed lint does not exist: {replace}"); + }; + + (ids, Symbol::intern(&replace)) + } + + CheckLintNameResult::Removed(ref reason) => { + if self.lint_added_lints { + let name = tool_name + .map(|tool| format!("{tool}::{lint_name}")) + .unwrap_or(lint_name); + self.emit_span_lint( + RENAMED_AND_REMOVED_LINTS, + sp.into(), + RemovedLint { name: name.as_str(), reason }, + ); } - }; + continue; + } - let src = LintLevelSource::Node { name, span: sp, reason }; - for &id in ids { - if self.check_gated_lint(id, sp, false) { - self.insert_spec(id, LevelSpec::new(level, lint_id, src)); + CheckLintNameResult::NoLint(suggestion) => { + if self.lint_added_lints { + let name = tool_name + .map(|tool| format!("{tool}::{lint_name}")) + .unwrap_or(lint_name); + let suggestion = suggestion.map(|(replace, from_rustc)| { + UnknownLintSuggestion::WithSpan { suggestion: sp, replace, from_rustc } + }); + self.emit_span_lint( + UNKNOWN_LINTS, + sp.into(), + UnknownLint { name, suggestion }, + ); } + continue; } + }; - // This checks for instances where the user writes - // `#[expect(unfulfilled_lint_expectations)]` in that case we want to avoid - // overriding the lint level but instead add an expectation that can't be - // fulfilled. The lint message will include an explanation, that the - // `unfulfilled_lint_expectations` lint can't be expected. - if let (Level::Expect, Some(expect_id)) = (level, lint_id) { - // The `unfulfilled_lint_expectations` lint is not part of any lint - // groups. Therefore. we only need to check the slice if it contains a - // single lint. - let is_unfulfilled_lint_expectations = match ids { - [lint] => *lint == LintId::of(UNFULFILLED_LINT_EXPECTATIONS), - _ => false, - }; - self.provider.push_expectation( - expect_id, - LintExpectation::new( - reason, - sp, - is_unfulfilled_lint_expectations, - tool_name, - ), - ); + let src = LintLevelSource::Node { name, span: sp, reason }; + for &id in ids { + if self.check_gated_lint(id, sp, false) { + self.insert_spec(id, LevelSpec::new(level, lint_id, src)); } } + + // This checks for instances where the user writes + // `#[expect(unfulfilled_lint_expectations)]` in that case we want to avoid + // overriding the lint level but instead add an expectation that can't be + // fulfilled. The lint message will include an explanation, that the + // `unfulfilled_lint_expectations` lint can't be expected. + if let (Level::Expect, Some(expect_id)) = (level, lint_id) { + // The `unfulfilled_lint_expectations` lint is not part of any lint + // groups. Therefore. we only need to check the slice if it contains a + // single lint. + let is_unfulfilled_lint_expectations = match ids { + [lint] => *lint == LintId::of(UNFULFILLED_LINT_EXPECTATIONS), + _ => false, + }; + self.provider.push_expectation( + expect_id, + LintExpectation::new(reason, sp, is_unfulfilled_lint_expectations, tool_name), + ); + } } if self.lint_added_lints && !is_crate_node { diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index ee858550c978f..94574384c1a12 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -10,6 +10,7 @@ rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } +rustc_attr_ir = { path = "../rustc_attr_ir" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 872ffec45f30a..43a04a8b6c4dc 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -84,10 +84,10 @@ that contains only loops and breakable blocks. It tracks where a `break`, use std::mem; use interpret::ErrorHandled; +use rustc_attr_ir::find_attr; use rustc_data_structures::fx::FxHashMap; use rustc_hir::HirId; use rustc_index::{IndexSlice, IndexVec}; -use rustc_lint_defs::Level; use rustc_middle::middle::region; use rustc_middle::mir::{self, *}; use rustc_middle::thir::{AdtExpr, AdtExprBase, ArmId, ExprId, ExprKind}; @@ -1291,13 +1291,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // This is a moderately common case, mostly hit for previously unseen nodes. break; } - - if self - .tcx - .hir_attrs(id) - .iter() - .any(|attr| Level::from_opt_symbol(attr.name()).is_some()) - { + if find_attr!(self.tcx, id, LintCheck(_)) { // This is a rare case. It's for a node path that doesn't reach the root due to an // intervening lint level attribute. This result doesn't get cached. return id; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 79987b86385ef..a392cb8b4d60b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -9,7 +9,7 @@ use std::cell::Cell; use std::slice; use rustc_abi::ExternAbi; -use rustc_ast::MetaItemKind; +use rustc_attr_ir::lint::LintCheck; use rustc_attr_parsing::AttributeParser; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::{DiagCtxtHandle, IntoDiagArg, MultiSpan, msg}; @@ -137,13 +137,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match attr { Attribute::Parsed(attr_kind) => { self.check_one_parsed_attribute(hir_id, span, target, item, attr_kind); - self.check_unused_attribute(hir_id, attr); } Attribute::Unparsed(_) => { match attr.path().as_slice() { - // ok - [sym::allow | sym::expect | sym::warn | sym::deny | sym::forbid, ..] => {} - [name, rest @ ..] => { if BUILTIN_ATTRIBUTE_SET.contains(name) { if rest.len() > 0 @@ -165,8 +161,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [] => unreachable!(), } - - self.check_unused_attribute(hir_id, attr); } } } @@ -235,6 +229,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::Linkage(_linkage, span) => { self.check_linkage(*span, hir_id, target, item) } + AttributeKind::LintCheck(lints) => self.check_lint_check(hir_id, lints), // All of the following attributes have no specific checks. // tidy-alphabetical-start @@ -1315,75 +1310,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) { - // Warn on useless empty attributes. - // FIXME(jdonszelmann): this lint should be moved to attribute parsing, see `AcceptContext::warn_empty_attribute` - let note = - if attr.has_any_name(&[sym::allow, sym::expect, sym::warn, sym::deny, sym::forbid]) - && attr.meta_item_list().is_some_and(|list| list.is_empty()) - { - diagnostics::UnusedNote::EmptyList { name: attr.name().unwrap() } - } else if attr.has_any_name(&[ - sym::allow, - sym::warn, - sym::deny, - sym::forbid, - sym::expect, - ]) && let Some(meta) = attr.meta_item_list() - && let [meta] = meta.as_slice() - && let Some(item) = meta.meta_item() - && let MetaItemKind::NameValue(_) = &item.kind - && item.path == sym::reason - { - diagnostics::UnusedNote::NoLints { name: attr.name().unwrap() } - } else if attr.has_any_name(&[ - sym::allow, - sym::warn, - sym::deny, - sym::forbid, - sym::expect, - ]) && let Some(meta) = attr.meta_item_list() - && meta.iter().any(|meta| { - meta.meta_item().map_or(false, |item| { - item.path == sym::linker_messages || item.path == sym::linker_info - }) - }) - { - if hir_id != CRATE_HIR_ID { - return; - } else { - let never_needs_link = self - .tcx - .crate_types() - .iter() - .all(|kind| matches!(kind, CrateType::Rlib | CrateType::StaticLib)); - if never_needs_link { - diagnostics::UnusedNote::LinkerMessagesBinaryCrateOnly - } else { - return; - } - } - } else if hir_id == CRATE_HIR_ID - && attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect]) - && let Some(meta) = attr.meta_item_list() - && meta.iter().any(|meta| { - meta.meta_item().is_some_and(|item| item.path == sym::dead_code_pub_in_binary) - }) - && !self.tcx.crate_types().contains(&CrateType::Executable) - { - diagnostics::UnusedNote::NoEffectDeadCodePubInBinary - } else { - return; - }; - - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - diagnostics::Unused { attr_span: attr.span(), note }, - ); - } - /// A best effort attempt to create an error for a mismatching proc macro signature. /// /// If this best effort goes wrong, it will just emit a worse error later (see #102923) @@ -1584,6 +1510,46 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => {} } } + + fn check_lint_check(&self, hir_id: HirId, lints: &[LintCheck]) { + for LintCheck { name, span, .. } in lints { + match &**name { + [sym::dead_code_pub_in_binary] => { + if !self.tcx.crate_types().contains(&CrateType::Executable) { + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + *span, + diagnostics::Unused { + attr_span: *span, + note: diagnostics::UnusedNote::NoEffectDeadCodePubInBinary, + }, + ); + } + } + [sym::linker_messages | sym::linker_info] => { + if hir_id == CRATE_HIR_ID + && self + .tcx + .crate_types() + .iter() + .all(|kind| matches!(kind, CrateType::Rlib | CrateType::StaticLib)) + { + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + *span, + diagnostics::Unused { + attr_span: *span, + note: diagnostics::UnusedNote::LinkerMessagesBinaryCrateOnly, + }, + ); + } + } + _ => {} + } + } + } } impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { diff --git a/compiler/rustc_passes/src/diagnostics.rs b/compiler/rustc_passes/src/diagnostics.rs index 55f8ac9a585de..0f5041dd1ae63 100644 --- a/compiler/rustc_passes/src/diagnostics.rs +++ b/compiler/rustc_passes/src/diagnostics.rs @@ -215,10 +215,6 @@ pub(crate) enum MacroExport { #[derive(Subdiagnostic)] pub(crate) enum UnusedNote { - #[note("attribute `{$name}` with an empty list has no effect")] - EmptyList { name: Symbol }, - #[note("attribute `{$name}` without any lints has no effect")] - NoLints { name: Symbol }, #[note( "the `linker_messages` and `linker_info` lints can only be controlled at the root of a crate that needs to be linked" )] diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs index 10814cdb4c585..5a763e8f54b92 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs @@ -3,11 +3,13 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::Msrv; use clippy_utils::source::{IntoSpan as _, SpanExt as _, snippet, snippet_block_with_applicability}; use clippy_utils::{can_use_if_let_chains, span_contains_cfg, span_contains_non_whitespace, sym, tokenize_with_text}; -use rustc_ast::{BinOpKind, MetaItemInner}; +use rustc_ast::BinOpKind; +use rustc_attr_ir::lint::LintCheckKind; +use rustc_attr_ir::{Attribute, AttributeKind}; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, StmtKind}; use rustc_lexer::TokenKind; -use rustc_lint::{LateContext, LateLintPass, Level, impl_lint_pass}; +use rustc_lint::{LateContext, LateLintPass, impl_lint_pass}; use rustc_span::{BytePos, Span, Symbol}; declare_clippy_lint! { @@ -238,17 +240,23 @@ impl CollapsibleIf { !span_contains_non_whitespace(cx, span, self.lint_commented_code) }, - [attr] - if matches!(Level::from_opt_symbol(attr.name()), Some(Level::Expect)) - && let Some(metas) = attr.meta_item_list() - && let Some(MetaItemInner::MetaItem(meta_item)) = metas.first() - && let [tool, lint_name] = meta_item.path.segments.as_slice() - && tool.ident.name == sym::clippy - && [expected_lint_name, sym::style, sym::all].contains(&lint_name.ident.name) => + [Attribute::Parsed(AttributeKind::LintCheck(lints))] + if lints + .iter() + .filter(|lint| matches!(lint.kind, LintCheckKind::Expect)) + .filter_map(|lint| { + if let [sym::clippy, lint_name] = &*lint.name { + Some(lint_name) + } else { + None + } + }) + .any(|lint| [expected_lint_name, sym::style, sym::all].contains(lint)) => { + let attr_span = lints.first().unwrap().attr_span.to(lints.last().unwrap().attr_span); // There is an `expect` attribute -- check that there is no _other_ significant text - let span_before_attr = inner_if.span.split_at(1).1.until(attr.span()); - let span_after_attr = attr.span().between(inner_if_expr.span); + let span_before_attr = inner_if.span.split_at(1).1.until(attr_span); + let span_after_attr = attr_span.between(inner_if_expr.span); !span_contains_non_whitespace(cx, span_before_attr, self.lint_commented_code) && !span_contains_non_whitespace(cx, span_after_attr, self.lint_commented_code) }, diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs index 39be16b947a4c..a5bac01d2bc53 100644 --- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs @@ -2,6 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::fulfill_or_allowed; use clippy_utils::source::snippet; +use rustc_attr_ir::find_attr; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::{self as hir, ExprKind}; @@ -183,8 +184,10 @@ fn suggestion<'tcx>( } fn field_with_attrs_span(tcx: TyCtxt<'_>, field: &hir::ExprField<'_>) -> Span { - if let Some(attr) = tcx.hir_attrs(field.hir_id).first() { - field.span.with_lo(attr.span().lo()) + if let Some(lints) = find_attr!(tcx, field.hir_id, LintCheck(lints) => lints) { + field.span.with_lo(lints.first().unwrap().attr_span.lo()) + } else if let Some(cfg_span) = find_attr!(tcx, field.hir_id, CfgTrace(cfgs) => cfgs[0].1) { + field.span.with_lo(cfg_span.lo()) } else { field.span } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index e1a1055b609dd..034b2764f1cac 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -26,6 +26,7 @@ extern crate rustc_abi; extern crate rustc_arena; extern crate rustc_ast; extern crate rustc_ast_pretty; +extern crate rustc_attr_ir; extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_hir; diff --git a/src/tools/clippy/clippy_lints/src/returns/let_and_return.rs b/src/tools/clippy/clippy_lints/src/returns/let_and_return.rs index 33d3e15412060..f4e17571173e1 100644 --- a/src/tools/clippy/clippy_lints/src/returns/let_and_return.rs +++ b/src/tools/clippy/clippy_lints/src/returns/let_and_return.rs @@ -5,9 +5,10 @@ use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::visitors::for_each_expr; use clippy_utils::{binary_expr_needs_parentheses, fn_def_id, span_contains_non_whitespace}; use core::ops::ControlFlow; +use rustc_attr_ir::find_attr; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, PatKind, Stmt, StmtKind}; -use rustc_lint::{LateContext, Level, LintContext as _}; +use rustc_lint::{LateContext, LintContext as _}; use rustc_middle::ty::GenericArgKind; use rustc_span::edition::Edition; @@ -91,11 +92,7 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) /// or if there is only whitespace between `let` and return expression. /// Non-lint attrs like `#[cfg]` should still block. fn has_lint_attrs_or_only_whitespace_between(cx: &LateContext<'_>, retexpr: &Expr<'_>, stmt: &Stmt<'_>) -> bool { - // TODO: Turn into find_attr! when lint level attr parsing is done. - let retexpr_attrs = cx.tcx.hir_attrs(retexpr.hir_id); + let retexpr_lintcheck_attr = find_attr!(cx.tcx, retexpr.hir_id, LintCheck(_)); - retexpr_attrs - .iter() - .any(|a| a.name().is_some_and(|name| Level::from_symbol(name).is_some())) - || !span_contains_non_whitespace(cx, stmt.span.between(retexpr.span), false) + retexpr_lintcheck_attr || !span_contains_non_whitespace(cx, stmt.span.between(retexpr.span), false) } diff --git a/src/tools/clippy/clippy_lints/src/returns/needless_return.rs b/src/tools/clippy/clippy_lints/src/returns/needless_return.rs index eab681a4cb720..f7d66d04a5436 100644 --- a/src/tools/clippy/clippy_lints/src/returns/needless_return.rs +++ b/src/tools/clippy/clippy_lints/src/returns/needless_return.rs @@ -4,12 +4,14 @@ use clippy_utils::{ binary_expr_needs_parentheses, is_from_proc_macro, leaks_droppable_temporary_with_limited_lifetime, span_contains_cfg, span_find_starting_semi, sym, }; -use rustc_ast::MetaItemInner; + +use rustc_attr_ir::lang_items::LangItem; +use rustc_attr_ir::lint::LintCheckKind; +use rustc_attr_ir::{Attribute, AttributeKind}; use rustc_errors::Applicability; -use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Expr, ExprKind, HirId, MatchSource, StmtKind}; -use rustc_lint::{LateContext, Level, LintContext as _}; +use rustc_lint::{LateContext, LintContext as _}; use rustc_middle::ty::{self, Ty}; use rustc_span::{BytePos, Pos as _, Span}; use std::borrow::Cow; @@ -181,17 +183,19 @@ fn check_final_expr<'tcx>( // actually fulfill the expectation (clippy::#12998) match cx.tcx.hir_attrs(expr.hir_id) { [] => {}, - [attr] => { - if matches!(Level::from_opt_symbol(attr.name()), Some(Level::Expect)) - && let metas = attr.meta_item_list() - && let Some(lst) = metas - && let [MetaItemInner::MetaItem(meta_item), ..] = lst.as_slice() - && let [tool, lint_name] = meta_item.path.segments.as_slice() - && tool.ident.name == sym::clippy - && matches!( - lint_name.ident.name, - sym::needless_return | sym::style | sym::all | sym::warnings - ) + [Attribute::Parsed(AttributeKind::LintCheck(lints))] => { + if lints + .iter() + .filter(|lint| matches!(lint.kind, LintCheckKind::Expect)) + .any(|lint| { + matches!( + &*lint.name, + [ + sym::clippy, + sym::needless_return | sym::style | sym::all | sym::warnings + ] + ) + }) { // This is an expectation of the `needless_return` lint } else { diff --git a/tests/pretty/delegation/generics.pp b/tests/pretty/delegation/generics.pp index f5429c3c26a75..87b523f16e19b 100644 --- a/tests/pretty/delegation/generics.pp +++ b/tests/pretty/delegation/generics.pp @@ -1,12 +1,13 @@ -//@ pretty-compare-only -//@ pretty-mode:hir -//@ pp-exact:generics.pp - -#![allow(incomplete_features)] +#![attr = LintCheck([LintCheck {name: ["incomplete_features"], attr_index: 0, +lint_index: 0, kind: Allow}])] #![attr = Feature([fn_delegation#0])] extern crate std; #[attr = PreludeImport] use ::std::prelude::rust_2015::*; +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:generics.pp + mod free_to_trait { trait Trait<'a, XX, Y, T = (), const N: usize = 2> { diff --git a/tests/pretty/delegation/inherit-attributes.pp b/tests/pretty/delegation/inherit-attributes.pp index a45eb5a1c5f38..27fb884fcd25c 100644 --- a/tests/pretty/delegation/inherit-attributes.pp +++ b/tests/pretty/delegation/inherit-attributes.pp @@ -1,14 +1,15 @@ +#![attr = LintCheck([LintCheck {name: ["incomplete_features"], attr_index: 0, +lint_index: 0, kind: Allow}])] +#![attr = Feature([fn_delegation#0])] +extern crate std; +#[attr = PreludeImport] +use std::prelude::rust_2021::*; //@ edition:2021 //@ aux-crate:to_reuse_functions=to-reuse-functions.rs //@ pretty-mode:hir //@ pretty-compare-only //@ pp-exact:inherit-attributes.pp -#![allow(incomplete_features)] -#![attr = Feature([fn_delegation#0])] -extern crate std; -#[attr = PreludeImport] -use std::prelude::rust_2021::*; extern crate to_reuse_functions; diff --git a/tests/pretty/delegation/inline-attribute.pp b/tests/pretty/delegation/inline-attribute.pp index 361eb56f558f4..a304748ed1cfe 100644 --- a/tests/pretty/delegation/inline-attribute.pp +++ b/tests/pretty/delegation/inline-attribute.pp @@ -1,12 +1,13 @@ -//@ pretty-compare-only -//@ pretty-mode:hir -//@ pp-exact:inline-attribute.pp - -#![allow(incomplete_features)] +#![attr = LintCheck([LintCheck {name: ["incomplete_features"], attr_index: 0, +lint_index: 0, kind: Allow}])] #![attr = Feature([fn_delegation#0])] extern crate std; #[attr = PreludeImport] use ::std::prelude::rust_2015::*; +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:inline-attribute.pp + mod to_reuse { fn foo(x: usize) -> usize { x } diff --git a/tests/pretty/hir-delegation.pp b/tests/pretty/hir-delegation.pp index 375460e86542b..212026532ecfc 100644 --- a/tests/pretty/hir-delegation.pp +++ b/tests/pretty/hir-delegation.pp @@ -1,12 +1,13 @@ -//@ pretty-compare-only -//@ pretty-mode:hir -//@ pp-exact:hir-delegation.pp - -#![allow(incomplete_features)] +#![attr = LintCheck([LintCheck {name: ["incomplete_features"], attr_index: 0, +lint_index: 0, kind: Allow}])] #![attr = Feature([fn_delegation#0])] extern crate std; #[attr = PreludeImport] use ::std::prelude::rust_2015::*; +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:hir-delegation.pp + fn b(e: C) { } diff --git a/tests/pretty/hir-lifetimes.pp b/tests/pretty/hir-lifetimes.pp index c35a40eed0c50..2a33aec88b4cd 100644 --- a/tests/pretty/hir-lifetimes.pp +++ b/tests/pretty/hir-lifetimes.pp @@ -1,13 +1,14 @@ +#![attr = LintCheck([LintCheck {name: ["unused"], attr_index: 0, +lint_index: 0, kind: Allow}])] +extern crate std; +#[attr = PreludeImport] +use ::std::prelude::rust_2015::*; //@ pretty-compare-only //@ pretty-mode:hir //@ pp-exact:hir-lifetimes.pp // This tests the pretty-printing of lifetimes in lots of ways. -#![allow(unused)] -extern crate std; -#[attr = PreludeImport] -use ::std::prelude::rust_2015::*; struct Foo<'a> { x: &'a u32, diff --git a/tests/pretty/pin-ergonomics-hir.pp b/tests/pretty/pin-ergonomics-hir.pp index 6c9dec2bfb1fb..48a007fb34121 100644 --- a/tests/pretty/pin-ergonomics-hir.pp +++ b/tests/pretty/pin-ergonomics-hir.pp @@ -1,12 +1,14 @@ -//@ pretty-compare-only -//@ pretty-mode:hir -//@ pp-exact:pin-ergonomics-hir.pp - -#![allow(dead_code, incomplete_features)] #![attr = Feature([pin_ergonomics#0])] +#![attr = LintCheck([LintCheck {name: ["dead_code"], attr_index: 0, +lint_index: 0, kind: Allow}, LintCheck {name: ["incomplete_features"], +attr_index: 0, lint_index: 1, kind: Allow}])] extern crate std; #[attr = PreludeImport] use ::std::prelude::rust_2015::*; +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:pin-ergonomics-hir.pp + use std::pin::Pin; diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 72e7776e09209..ee6ba9fbc7495 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -28,86 +28,6 @@ error[E0463]: can't find crate for `wloop` LL | extern crate wloop; | ^^^^^^^^^^^^^^^^^^^ can't find crate -error: malformed `allow` attribute input - --> $DIR/malformed-attrs.rs:179:1 - | -LL | #[allow] - | ^^^^^^^^ - | - = note: for more information, visit -help: the following are the possible correct uses - | -LL | #[allow(lint1)] - | +++++++ -LL | #[allow(lint1, lint2, ...)] - | +++++++++++++++++++ -LL | #[allow(lint1, lint2, lint3, reason = "...")] - | +++++++++++++++++++++++++++++++++++++ - -error: malformed `expect` attribute input - --> $DIR/malformed-attrs.rs:181:1 - | -LL | #[expect] - | ^^^^^^^^^ - | - = note: for more information, visit -help: the following are the possible correct uses - | -LL | #[expect(lint1)] - | +++++++ -LL | #[expect(lint1, lint2, ...)] - | +++++++++++++++++++ -LL | #[expect(lint1, lint2, lint3, reason = "...")] - | +++++++++++++++++++++++++++++++++++++ - -error: malformed `warn` attribute input - --> $DIR/malformed-attrs.rs:183:1 - | -LL | #[warn] - | ^^^^^^^ - | - = note: for more information, visit -help: the following are the possible correct uses - | -LL | #[warn(lint1)] - | +++++++ -LL | #[warn(lint1, lint2, ...)] - | +++++++++++++++++++ -LL | #[warn(lint1, lint2, lint3, reason = "...")] - | +++++++++++++++++++++++++++++++++++++ - -error: malformed `deny` attribute input - --> $DIR/malformed-attrs.rs:185:1 - | -LL | #[deny] - | ^^^^^^^ - | - = note: for more information, visit -help: the following are the possible correct uses - | -LL | #[deny(lint1)] - | +++++++ -LL | #[deny(lint1, lint2, ...)] - | +++++++++++++++++++ -LL | #[deny(lint1, lint2, lint3, reason = "...")] - | +++++++++++++++++++++++++++++++++++++ - -error: malformed `forbid` attribute input - --> $DIR/malformed-attrs.rs:187:1 - | -LL | #[forbid] - | ^^^^^^^^^ - | - = note: for more information, visit -help: the following are the possible correct uses - | -LL | #[forbid(lint1)] - | +++++++ -LL | #[forbid(lint1, lint2, ...)] - | +++++++++++++++++++ -LL | #[forbid(lint1, lint2, lint3, reason = "...")] - | +++++++++++++++++++++++++++++++++++++ - error: the `proc_macro` attribute is only usable with crates of the `proc-macro` crate type --> $DIR/malformed-attrs.rs:106:3 | @@ -714,6 +634,86 @@ error[E0539]: malformed `linkage` attribute input LL | #[linkage] | ^^^^^^^ expected this to be of the form `linkage = "..."` +error[E0539]: malformed `allow` attribute input + --> $DIR/malformed-attrs.rs:179:3 + | +LL | #[allow] + | ^^^^^ expected this to be a list + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL | #[allow(lint1)] + | +++++++ +LL | #[allow(lint1, lint2, ...)] + | +++++++++++++++++++ +LL | #[allow(lint1, lint2, lint3, reason = "...")] + | +++++++++++++++++++++++++++++++++++++ + +error[E0539]: malformed `expect` attribute input + --> $DIR/malformed-attrs.rs:181:3 + | +LL | #[expect] + | ^^^^^^ expected this to be a list + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL | #[expect(lint1)] + | +++++++ +LL | #[expect(lint1, lint2, ...)] + | +++++++++++++++++++ +LL | #[expect(lint1, lint2, lint3, reason = "...")] + | +++++++++++++++++++++++++++++++++++++ + +error[E0539]: malformed `warn` attribute input + --> $DIR/malformed-attrs.rs:183:3 + | +LL | #[warn] + | ^^^^ expected this to be a list + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL | #[warn(lint1)] + | +++++++ +LL | #[warn(lint1, lint2, ...)] + | +++++++++++++++++++ +LL | #[warn(lint1, lint2, lint3, reason = "...")] + | +++++++++++++++++++++++++++++++++++++ + +error[E0539]: malformed `deny` attribute input + --> $DIR/malformed-attrs.rs:185:3 + | +LL | #[deny] + | ^^^^ expected this to be a list + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL | #[deny(lint1)] + | +++++++ +LL | #[deny(lint1, lint2, ...)] + | +++++++++++++++++++ +LL | #[deny(lint1, lint2, lint3, reason = "...")] + | +++++++++++++++++++++++++++++++++++++ + +error[E0539]: malformed `forbid` attribute input + --> $DIR/malformed-attrs.rs:187:3 + | +LL | #[forbid] + | ^^^^^^ expected this to be a list + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL | #[forbid(lint1)] + | +++++++ +LL | #[forbid(lint1, lint2, ...)] + | +++++++++++++++++++ +LL | #[forbid(lint1, lint2, lint3, reason = "...")] + | +++++++++++++++++++++++++++++++++++++ + error[E0539]: malformed `debugger_visualizer` attribute input --> $DIR/malformed-attrs.rs:189:3 | diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs index bd136e64d3f92..33324685a84f4 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs @@ -21,15 +21,18 @@ pub fn c() {} pub fn d() {} #[unsafe(allow(dead_code))] -//~^ ERROR: is not an unsafe attribute +//~^ ERROR: allow` is not an unsafe attribute +//~| ERROR: `allow` is not an unsafe attribute +//~| ERROR: `allow` is not an unsafe attribute pub fn e() {} #[unsafe(allow(unsafe(dead_code)))] -//~^ ERROR: is not an unsafe attribute -//~| ERROR: malformed lint attribute input -//~| ERROR: malformed lint attribute input +//~^ ERROR: allow` is not an unsafe attribute +//~| ERROR: `allow` is not an unsafe attribute +//~| ERROR: `allow` is not an unsafe attribute +//~| ERROR: expected identifier, found keyword `unsafe` +//~| ERROR: expected identifier, found keyword `unsafe` //~| ERROR: expected identifier, found keyword `unsafe` -//~| ERROR: malformed lint attribute input //~| ERROR: malformed lint attribute input //~| ERROR: malformed lint attribute input //~| ERROR: malformed lint attribute input diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr index 3b5baaace1a50..04e8c4d2dd453 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr @@ -1,19 +1,21 @@ -error[E0452]: malformed lint attribute input - --> $DIR/proc-unsafe-attributes.rs:27:16 +error: `allow` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:23:3 | -LL | #[unsafe(allow(unsafe(dead_code)))] - | ^^^^^^^^^^^^^^^^^ bad attribute argument +LL | #[unsafe(allow(dead_code))] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes -error[E0452]: malformed lint attribute input - --> $DIR/proc-unsafe-attributes.rs:27:16 +error: `allow` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:29:3 | LL | #[unsafe(allow(unsafe(dead_code)))] - | ^^^^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^ this is not an unsafe attribute | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: extraneous unsafe is not allowed in attributes error: expected identifier, found keyword `unsafe` - --> $DIR/proc-unsafe-attributes.rs:27:16 + --> $DIR/proc-unsafe-attributes.rs:29:16 | LL | #[unsafe(allow(unsafe(dead_code)))] | ^^^^^^ expected identifier, found keyword @@ -23,6 +25,12 @@ help: escape `unsafe` to use it as an identifier LL | #[unsafe(allow(r#unsafe(dead_code)))] | ++ +error[E0452]: malformed lint attribute input + --> $DIR/proc-unsafe-attributes.rs:29:16 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^^^^^^^^^^^^ bad attribute argument + error: the `proc_macro` attribute is only usable with crates of the `proc-macro` crate type --> $DIR/proc-unsafe-attributes.rs:1:10 | @@ -47,16 +55,38 @@ error: the `proc_macro_attribute` attribute is only usable with crates of the `p LL | #[unsafe(proc_macro_attribute)] | ^^^^^^^^^^^^^^^^^^^^ -error[E0452]: malformed lint attribute input - --> $DIR/proc-unsafe-attributes.rs:27:16 +error: `allow` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:23:3 + | +LL | #[unsafe(allow(dead_code))] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `allow` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:29:3 | LL | #[unsafe(allow(unsafe(dead_code)))] - | ^^^^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^ this is not an unsafe attribute | + = note: extraneous unsafe is not allowed in attributes = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error: expected identifier, found keyword `unsafe` + --> $DIR/proc-unsafe-attributes.rs:29:16 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^ expected identifier, found keyword + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: escape `unsafe` to use it as an identifier + | +LL | #[unsafe(allow(r#unsafe(dead_code)))] + | ++ + error[E0452]: malformed lint attribute input - --> $DIR/proc-unsafe-attributes.rs:27:16 + --> $DIR/proc-unsafe-attributes.rs:29:16 | LL | #[unsafe(allow(unsafe(dead_code)))] | ^^^^^^^^^^^^^^^^^ bad attribute argument @@ -123,32 +153,38 @@ LL | #[unsafe(allow(dead_code))] | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `allow` is not an unsafe attribute - --> $DIR/proc-unsafe-attributes.rs:27:3 + --> $DIR/proc-unsafe-attributes.rs:29:3 | LL | #[unsafe(allow(unsafe(dead_code)))] | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0452]: malformed lint attribute input - --> $DIR/proc-unsafe-attributes.rs:27:16 +error: expected identifier, found keyword `unsafe` + --> $DIR/proc-unsafe-attributes.rs:29:16 | LL | #[unsafe(allow(unsafe(dead_code)))] - | ^^^^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^ expected identifier, found keyword | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: escape `unsafe` to use it as an identifier + | +LL | #[unsafe(allow(r#unsafe(dead_code)))] + | ++ error[E0452]: malformed lint attribute input - --> $DIR/proc-unsafe-attributes.rs:27:16 + --> $DIR/proc-unsafe-attributes.rs:29:16 | LL | #[unsafe(allow(unsafe(dead_code)))] | ^^^^^^^^^^^^^^^^^ bad attribute argument | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 18 previous errors +error: aborting due to 21 previous errors Some errors have detailed explanations: E0452, E0565. For more information about an error, try `rustc --explain E0452`. diff --git a/tests/ui/eii/cfg_on_eii.stdout b/tests/ui/eii/cfg_on_eii.stdout index 1217ee5c6b2de..e78a0b7e09c52 100644 --- a/tests/ui/eii/cfg_on_eii.stdout +++ b/tests/ui/eii/cfg_on_eii.stdout @@ -1,10 +1,10 @@ -//@ compile-flags: -Z unpretty=hir,typed - -#![deny(deprecated)] #![attr = Feature([extern_item_impls#0])] +#![attr = LintCheck([LintCheck {name: ["deprecated"], attr_index: 0, +lint_index: 0, kind: Deny}])] extern crate std; #[attr = PreludeImport] use ::std::prelude::rust_2015::*; +//@ compile-flags: -Z unpretty=hir,typed const _: () = ({ diff --git a/tests/ui/inference/issue-71309.stderr b/tests/ui/inference/issue-71309.stderr index 673649c767e3d..a96cbccf02708 100644 --- a/tests/ui/inference/issue-71309.stderr +++ b/tests/ui/inference/issue-71309.stderr @@ -7,8 +7,8 @@ LL | let y: u32 = x?; = note: `?` operator cannot convert from `i32` to `u32` help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit | -LL | let y: u32 = x?.try_into().unwrap(); - | ++++++++++++++++++++ +LL | let y: u32 = (x?).try_into().unwrap(); + | + +++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/lint/dead-code-pub-in-binary/library.stderr b/tests/ui/lint/dead-code-pub-in-binary/library.stderr index 8ac71b01c6627..af3a6a104ad55 100644 --- a/tests/ui/lint/dead-code-pub-in-binary/library.stderr +++ b/tests/ui/lint/dead-code-pub-in-binary/library.stderr @@ -1,8 +1,8 @@ warning: unused attribute - --> $DIR/library.rs:2:1 + --> $DIR/library.rs:2:9 | LL | #![deny(dead_code_pub_in_binary)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | = note: the `dead_code_pub_in_binary` lint has no effect in library crates = note: requested on the command line with `-W unused-attributes` diff --git a/tests/ui/lint/empty-lint-attributes.rs b/tests/ui/lint/empty-lint-attributes.rs index 4f550eae06363..9406925444b74 100644 --- a/tests/ui/lint/empty-lint-attributes.rs +++ b/tests/ui/lint/empty-lint-attributes.rs @@ -3,13 +3,21 @@ // Empty (and reason-only) lint attributes are legal—although we may want to // lint them in the future (Issue #55112). -#![allow()] //~ WARN unused attribute -#![warn(reason = "observationalism")] //~ WARN unused attribute +#![allow()] +//~^ WARN unused attribute +//~| WARN unused attribute +#![warn(reason = "observationalism")] +//~^ WARN unused attribute +//~| WARN unused attribute -#[forbid()] //~ WARN unused attribute +#[forbid()] +//~^ WARN unused attribute +//~| WARN unused attribute fn devoir() {} -#[deny(reason = "ultion")] //~ WARN unused attribute +#[deny(reason = "ultion")] +//~^ WARN unused attribute +//~| WARN unused attribute fn waldgrave() {} fn main() {} diff --git a/tests/ui/lint/empty-lint-attributes.stderr b/tests/ui/lint/empty-lint-attributes.stderr index 5bf8ae1e9ee7f..0c9b9771d007a 100644 --- a/tests/ui/lint/empty-lint-attributes.stderr +++ b/tests/ui/lint/empty-lint-attributes.stderr @@ -1,14 +1,30 @@ +warning: unused attribute + --> $DIR/empty-lint-attributes.rs:6:1 + | +LL | #![allow()] + | ^^^^^^^^^^^ help: remove this attribute + | + = note: attribute `allow` with an empty list has no effect + = note: requested on the command line with `-W unused-attributes` + warning: unused attribute --> $DIR/empty-lint-attributes.rs:9:1 | +LL | #![warn(reason = "observationalism")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: attribute `warn` without any lints has no effect + +warning: unused attribute + --> $DIR/empty-lint-attributes.rs:13:1 + | LL | #[forbid()] | ^^^^^^^^^^^ help: remove this attribute | = note: attribute `forbid` with an empty list has no effect - = note: requested on the command line with `-W unused-attributes` warning: unused attribute - --> $DIR/empty-lint-attributes.rs:12:1 + --> $DIR/empty-lint-attributes.rs:18:1 | LL | #[deny(reason = "ultion")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute @@ -22,14 +38,34 @@ LL | #![allow()] | ^^^^^^^^^^^ help: remove this attribute | = note: attribute `allow` with an empty list has no effect + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: unused attribute - --> $DIR/empty-lint-attributes.rs:7:1 + --> $DIR/empty-lint-attributes.rs:9:1 | LL | #![warn(reason = "observationalism")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | = note: attribute `warn` without any lints has no effect + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: unused attribute + --> $DIR/empty-lint-attributes.rs:13:1 + | +LL | #[forbid()] + | ^^^^^^^^^^^ help: remove this attribute + | + = note: attribute `forbid` with an empty list has no effect + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: unused attribute + --> $DIR/empty-lint-attributes.rs:18:1 + | +LL | #[deny(reason = "ultion")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: attribute `deny` without any lints has no effect + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -warning: 4 warnings emitted +warning: 8 warnings emitted diff --git a/tests/ui/lint/inert-attr-macro.rs b/tests/ui/lint/inert-attr-macro.rs index 3c7542ff4d225..deb8995f36008 100644 --- a/tests/ui/lint/inert-attr-macro.rs +++ b/tests/ui/lint/inert-attr-macro.rs @@ -12,8 +12,10 @@ fn main() { // This does nothing, since `#[allow(warnings)]` is itself // an inert attribute on a macro call - #[allow(warnings)] #[inline] foo!(); //~ WARN unused attribute `allow` - //~^ WARN the `inline` attribute cannot be used on macro calls + #[allow(warnings)] #[inline] foo!(); + //~^ WARN the `allow` attribute cannot be used on macro calls + //~| WARN previously accepted + //~| WARN the `inline` attribute cannot be used on macro calls //~| WARN previously accepted // This does work, since the attribute is on a parent diff --git a/tests/ui/lint/inert-attr-macro.stderr b/tests/ui/lint/inert-attr-macro.stderr index dcb9fb3d61ce7..a13d17bd4b0c2 100644 --- a/tests/ui/lint/inert-attr-macro.stderr +++ b/tests/ui/lint/inert-attr-macro.stderr @@ -14,17 +14,15 @@ LL | #![warn(unused)] | ^^^^^^ = note: `#[warn(unused_attributes)]` implied by `#[warn(unused)]` -warning: unused attribute `allow` - --> $DIR/inert-attr-macro.rs:15:5 +warning: the `allow` attribute cannot be used on macro calls + --> $DIR/inert-attr-macro.rs:15:7 | LL | #[allow(warnings)] #[inline] foo!(); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^ | -note: the built-in attribute `allow` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/inert-attr-macro.rs:15:34 - | -LL | #[allow(warnings)] #[inline] foo!(); - | ^^^ + = help: the `allow` attribute can be applied to associated consts, associated types, break expressions, const parameters, constants, crates, data types, enum variants, extern crates, for loops, foreign modules, foreign statics, function params, functions, global asms, impl blocks, lifetime parameters, loops, macro defs, match arms, modules, pattern fields, statics, struct fields, trait aliases, traits, type aliases, type parameters, use statements, and while loops + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: placing this attribute on a macro invocation does nothing even if the macro expands to what would be a valid target for the attribute warning: the `inline` attribute cannot be used on macro calls --> $DIR/inert-attr-macro.rs:15:26 diff --git a/tests/ui/lint/linker-warning.stderr b/tests/ui/lint/linker-warning.stderr index 39e6522a45f66..22842a7141453 100644 --- a/tests/ui/lint/linker-warning.stderr +++ b/tests/ui/lint/linker-warning.stderr @@ -11,10 +11,10 @@ LL | #![warn(unused_attributes)] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/linker-warning.rs:4:1 + --> $DIR/linker-warning.rs:4:10 | LL | #![allow(linker_messages)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | ^^^^^^^^^^^^^^^ help: remove this attribute | = note: the `linker_messages` and `linker_info` lints can only be controlled at the root of a crate that needs to be linked diff --git a/tests/ui/lint/lint-malformed.stderr b/tests/ui/lint/lint-malformed.stderr index 25a4298bd75bf..7be928de86985 100644 --- a/tests/ui/lint/lint-malformed.stderr +++ b/tests/ui/lint/lint-malformed.stderr @@ -12,25 +12,6 @@ LL | #![allow(bar = "baz")] | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: malformed `deny` attribute input - --> $DIR/lint-malformed.rs:1:1 - | -LL | #![deny = "foo"] - | ^^^^^^^^^^^^^^^^ - | - = note: for more information, visit -help: the following are the possible correct uses - | -LL - #![deny = "foo"] -LL + #![deny(lint1)] - | -LL - #![deny = "foo"] -LL + #![deny(lint1, lint2, ...)] - | -LL - #![deny = "foo"] -LL + #![deny(lint1, lint2, lint3, reason = "...")] - | - error[E0452]: malformed lint attribute input --> $DIR/lint-malformed.rs:2:10 | @@ -47,6 +28,27 @@ LL | #![allow(bar = "baz")] | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0539]: malformed `deny` attribute input + --> $DIR/lint-malformed.rs:1:4 + | +LL | #![deny = "foo"] + | ^^^^^------- + | | + | expected this to be a list + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #![deny = "foo"] +LL + #![deny(lint1)] + | +LL - #![deny = "foo"] +LL + #![deny(lint1, lint2, ...)] + | +LL - #![deny = "foo"] +LL + #![deny(lint1, lint2, lint3, reason = "...")] + | + error[E0452]: malformed lint attribute input --> $DIR/lint-malformed.rs:2:10 | @@ -65,4 +67,5 @@ LL | #![allow(bar = "baz")] error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0452`. +Some errors have detailed explanations: E0452, E0539. +For more information about an error, try `rustc --explain E0452`. diff --git a/tests/ui/lint/pre-expansion-parsing.rs b/tests/ui/lint/pre-expansion-parsing.rs index 3df56775c6c5f..7cfc57ff4e903 100644 --- a/tests/ui/lint/pre-expansion-parsing.rs +++ b/tests/ui/lint/pre-expansion-parsing.rs @@ -4,7 +4,6 @@ #[expect[wut]] // OK #[expect(expect)] // OK #[expect(expect(expect))] //~ ERROR malformed lint attribute input - //~| ERROR malformed lint attribute input #[deny(({!}))] // OK #[expect[helix::]] // OK #[cfg(false)] diff --git a/tests/ui/lint/pre-expansion-parsing.stderr b/tests/ui/lint/pre-expansion-parsing.stderr index c0c4e792b676f..ecc8b7017d92d 100644 --- a/tests/ui/lint/pre-expansion-parsing.stderr +++ b/tests/ui/lint/pre-expansion-parsing.stderr @@ -4,14 +4,6 @@ error[E0452]: malformed lint attribute input LL | #[expect(expect(expect))] | ^^^^^^^^^^^^^^ bad attribute argument -error[E0452]: malformed lint attribute input - --> $DIR/pre-expansion-parsing.rs:6:10 - | -LL | #[expect(expect(expect))] - | ^^^^^^^^^^^^^^ bad attribute argument - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0452`. diff --git a/tests/ui/lint/reasons-erroneous.rs b/tests/ui/lint/reasons-erroneous.rs index 0aa46953bf1ac..38ad00da64cd7 100644 --- a/tests/ui/lint/reasons-erroneous.rs +++ b/tests/ui/lint/reasons-erroneous.rs @@ -1,11 +1,12 @@ //@ compile-flags: -Zdeduplicate-diagnostics=yes #![warn(absolute_paths_not_starting_with_crate, reason = 0)] -//~^ ERROR malformed lint attribute -//~| NOTE reason must be a string literal +//~^ ERROR malformed `warn` attribute input +//~| NOTE expected a string literal here +//~| NOTE for more information, visit #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")] -//~^ ERROR malformed lint attribute -//~| NOTE reason must be a string literal +//~^ ERROR malformed `warn` attribute input +//~| NOTE expected a normal string literal, not a byte string literal #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] //~^ ERROR malformed lint attribute //~| NOTE bad attribute argument diff --git a/tests/ui/lint/reasons-erroneous.stderr b/tests/ui/lint/reasons-erroneous.stderr index fcff88d8e0fa7..d771366d6168e 100644 --- a/tests/ui/lint/reasons-erroneous.stderr +++ b/tests/ui/lint/reasons-erroneous.stderr @@ -1,47 +1,66 @@ -error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:3:58 +error[E0539]: malformed `warn` attribute input + --> $DIR/reasons-erroneous.rs:3:4 | LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)] - | ^ reason must be a string literal + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^ + | | + | expected a string literal here + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #![warn(absolute_paths_not_starting_with_crate, reason = 0)] +LL + #![warn(lint1)] + | +LL - #![warn(absolute_paths_not_starting_with_crate, reason = 0)] +LL + #![warn(lint1, lint2, ...)] + | +LL - #![warn(absolute_paths_not_starting_with_crate, reason = 0)] +LL + #![warn(lint1, lint2, lint3, reason = "...")] + | -error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:6:40 +error[E0539]: malformed `warn` attribute input + --> $DIR/reasons-erroneous.rs:7:4 | LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider removing the prefix + | + = note: expected a normal string literal, not a byte string literal error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:9:29 + --> $DIR/reasons-erroneous.rs:10:29 | LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:12:22 + --> $DIR/reasons-erroneous.rs:13:22 | LL | #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:15:36 + --> $DIR/reasons-erroneous.rs:16:36 | LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:18:44 + --> $DIR/reasons-erroneous.rs:19:44 | LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")] | ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:21:25 + --> $DIR/reasons-erroneous.rs:22:25 | LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last warning: unknown lint: `reason` - --> $DIR/reasons-erroneous.rs:24:39 + --> $DIR/reasons-erroneous.rs:25:39 | LL | #![warn(missing_copy_implementations, reason)] | ^^^^^^ @@ -50,4 +69,5 @@ LL | #![warn(missing_copy_implementations, reason)] error: aborting due to 7 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0452`. +Some errors have detailed explanations: E0452, E0539. +For more information about an error, try `rustc --explain E0452`. diff --git a/tests/ui/lint/register-tool-lint.stderr b/tests/ui/lint/register-tool-lint.stderr index 7ebdbdec92972..1a20a9d0cd8f1 100644 --- a/tests/ui/lint/register-tool-lint.stderr +++ b/tests/ui/lint/register-tool-lint.stderr @@ -2,7 +2,7 @@ error[E0710]: unknown tool name `abc` found in scoped lint: `abc::my_lint` --> $DIR/register-tool-lint.rs:5:9 | LL | #![warn(abc::my_lint)] - | ^^^ + | ^^^^^^^^^^^^ | = help: add `#![register_tool(abc)]` to the crate root @@ -10,7 +10,7 @@ error[E0710]: unknown tool name `abc` found in scoped lint: `abc::my_lint` --> $DIR/register-tool-lint.rs:5:9 | LL | #![warn(abc::my_lint)] - | ^^^ + | ^^^^^^^^^^^^ | = help: add `#![register_tool(abc)]` to the crate root = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs b/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs index c93c94ae84a9a..52aa8c0980f7b 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs @@ -23,7 +23,9 @@ pub fn check_expect_on_item() { pub fn check_expect_on_macro() { // This should be fulfilled by the macro - #[expect(unused_variables)] //~ WARN unused attribute + #[expect(unused_variables)] + //~^ WARN the `expect` attribute cannot be used on macro call + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! trigger_unused_variables_macro!(); // FIXME: Lint attributes currently don't work directly on macros, and diff --git a/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.stderr b/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.stderr index f0ee27a99151f..aecb6dbbb708f 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.stderr @@ -1,14 +1,12 @@ -warning: unused attribute `expect` - --> $DIR/expect_lint_from_macro.rs:26:5 +warning: the `expect` attribute cannot be used on macro calls + --> $DIR/expect_lint_from_macro.rs:26:7 | LL | #[expect(unused_variables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ | -note: the built-in attribute `expect` will be ignored, since it's applied to the macro invocation `trigger_unused_variables_macro` - --> $DIR/expect_lint_from_macro.rs:27:5 - | -LL | trigger_unused_variables_macro!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: the `expect` attribute can be applied to associated consts, associated types, break expressions, const parameters, constants, crates, data types, enum variants, extern crates, for loops, foreign modules, foreign statics, function params, functions, global asms, impl blocks, lifetime parameters, loops, macro defs, match arms, modules, pattern fields, statics, struct fields, trait aliases, traits, type aliases, type parameters, use statements, and while loops + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: placing this attribute on a macro invocation does nothing even if the macro expands to what would be a valid target for the attribute = note: requested on the command line with `-W unused-attributes` warning: unused variable: `x` diff --git a/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.rs b/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.rs index a7767769344a2..2d14bcda47ee0 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.rs +++ b/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.rs @@ -1,10 +1,20 @@ #![deny(unused_attributes)] -#[allow(reason = "I want to allow something")]//~ ERROR unused attribute -#[expect(reason = "I don't know what I'm waiting for")]//~ ERROR unused attribute -#[warn(reason = "This should be warn by default")]//~ ERROR unused attribute -#[deny(reason = "All listed lints are denied")]//~ ERROR unused attribute -#[forbid(reason = "Just some reason")]//~ ERROR unused attribute +#[allow(reason = "I want to allow something")] +//~^ ERROR unused attribute +//~| ERROR unused attribute +#[expect(reason = "I don't know what I'm waiting for")] +//~^ ERROR unused attribute +//~| ERROR unused attribute +#[warn(reason = "This should be warn by default")] +//~^ ERROR unused attribute +//~| ERROR unused attribute +#[deny(reason = "All listed lints are denied")] +//~^ ERROR unused attribute +//~| ERROR unused attribute +#[forbid(reason = "Just some reason")] +//~^ ERROR unused attribute +//~| ERROR unused attribute #[allow(clippy::box_collection, reason = "This is still valid")] #[warn(dead_code, reason = "This is also reasonable")] diff --git a/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr b/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr index 7f01c2dc61beb..b19514804e44f 100644 --- a/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr +++ b/tests/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr @@ -12,7 +12,7 @@ LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/lint-attribute-only-with-reason.rs:4:1 + --> $DIR/lint-attribute-only-with-reason.rs:6:1 | LL | #[expect(reason = "I don't know what I'm waiting for")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute @@ -20,28 +20,73 @@ LL | #[expect(reason = "I don't know what I'm waiting for")] = note: attribute `expect` without any lints has no effect error: unused attribute - --> $DIR/lint-attribute-only-with-reason.rs:5:1 + --> $DIR/lint-attribute-only-with-reason.rs:9:1 | LL | #[warn(reason = "This should be warn by default")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | = note: attribute `warn` without any lints has no effect +error: unused attribute + --> $DIR/lint-attribute-only-with-reason.rs:12:1 + | +LL | #[deny(reason = "All listed lints are denied")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: attribute `deny` without any lints has no effect + +error: unused attribute + --> $DIR/lint-attribute-only-with-reason.rs:15:1 + | +LL | #[forbid(reason = "Just some reason")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: attribute `forbid` without any lints has no effect + +error: unused attribute + --> $DIR/lint-attribute-only-with-reason.rs:3:1 + | +LL | #[allow(reason = "I want to allow something")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: attribute `allow` without any lints has no effect + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error: unused attribute --> $DIR/lint-attribute-only-with-reason.rs:6:1 | +LL | #[expect(reason = "I don't know what I'm waiting for")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: attribute `expect` without any lints has no effect + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: unused attribute + --> $DIR/lint-attribute-only-with-reason.rs:9:1 + | +LL | #[warn(reason = "This should be warn by default")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: attribute `warn` without any lints has no effect + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: unused attribute + --> $DIR/lint-attribute-only-with-reason.rs:12:1 + | LL | #[deny(reason = "All listed lints are denied")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | = note: attribute `deny` without any lints has no effect + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: unused attribute - --> $DIR/lint-attribute-only-with-reason.rs:7:1 + --> $DIR/lint-attribute-only-with-reason.rs:15:1 | LL | #[forbid(reason = "Just some reason")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | = note: attribute `forbid` without any lints has no effect + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 5 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs b/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs index 28c2a2c33abeb..d3c4a205c4b1f 100644 --- a/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs +++ b/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.rs @@ -48,5 +48,6 @@ fn main() { // This `#[allow]` does not work, since the attribute gets dropped // when we expand the macro let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work); - //~^ WARN unused attribute + //~^ WARN the `allow` attribute cannot be used on macro calls + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } diff --git a/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr b/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr index 5a426be83f861..d5a8c8a187f68 100644 --- a/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr +++ b/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr @@ -31,17 +31,15 @@ LL | let _ = foo!(warn_in_expr); = note: for more information, see issue #79813 = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: unused attribute `allow` - --> $DIR/semicolon-in-expressions-from-macros.rs:50:13 +warning: the `allow` attribute cannot be used on macro calls + --> $DIR/semicolon-in-expressions-from-macros.rs:50:15 | LL | let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ | -note: the built-in attribute `allow` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/semicolon-in-expressions-from-macros.rs:50:60 - | -LL | let _ = #[allow(semicolon_in_expressions_from_macros)] foo!(allow_does_not_work); - | ^^^ + = help: the `allow` attribute can be applied to associated consts, associated types, break expressions, const parameters, constants, crates, data types, enum variants, expressions, extern crates, for loops, foreign modules, foreign statics, function params, functions, global asms, impl blocks, lifetime parameters, loops, macro defs, match arms, modules, pattern fields, statements, statics, struct fields, trait aliases, traits, type aliases, type parameters, use statements, and while loops + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: placing this attribute on a macro invocation does nothing even if the macro expands to what would be a valid target for the attribute = note: requested on the command line with `-W unused-attributes` warning: trailing semicolon in macro used in expression position diff --git a/tests/ui/lint/unused/empty-attributes.rs b/tests/ui/lint/unused/empty-attributes.rs index 027d30cce17f0..c60d19680bf1b 100644 --- a/tests/ui/lint/unused/empty-attributes.rs +++ b/tests/ui/lint/unused/empty-attributes.rs @@ -1,9 +1,19 @@ #![deny(unused_attributes)] -#![allow()] //~ ERROR unused attribute -#![expect()] //~ ERROR unused attribute -#![warn()] //~ ERROR unused attribute -#![deny()] //~ ERROR unused attribute -#![forbid()] //~ ERROR unused attribute +#![allow()] +//~^ ERROR unused attribute +//~| ERROR unused attribute +#![expect()] +//~^ ERROR unused attribute +//~| ERROR unused attribute +#![warn()] +//~^ ERROR unused attribute +//~| ERROR unused attribute +#![deny()] +//~^ ERROR unused attribute +//~| ERROR unused attribute +#![forbid()] +//~^ ERROR unused attribute +//~| ERROR unused attribute #![feature()] //~ ERROR unused attribute #[repr()] //~ ERROR unused attribute diff --git a/tests/ui/lint/unused/empty-attributes.stderr b/tests/ui/lint/unused/empty-attributes.stderr index 5b5ca73e5137e..8414b21cd4906 100644 --- a/tests/ui/lint/unused/empty-attributes.stderr +++ b/tests/ui/lint/unused/empty-attributes.stderr @@ -12,7 +12,7 @@ LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/empty-attributes.rs:3:1 + --> $DIR/empty-attributes.rs:5:1 | LL | #![expect()] | ^^^^^^^^^^^^ help: remove this attribute @@ -20,31 +20,76 @@ LL | #![expect()] = note: attribute `expect` with an empty list has no effect error: unused attribute - --> $DIR/empty-attributes.rs:4:1 + --> $DIR/empty-attributes.rs:8:1 | LL | #![warn()] | ^^^^^^^^^^ help: remove this attribute | = note: attribute `warn` with an empty list has no effect +error: unused attribute + --> $DIR/empty-attributes.rs:11:1 + | +LL | #![deny()] + | ^^^^^^^^^^ help: remove this attribute + | + = note: attribute `deny` with an empty list has no effect + +error: unused attribute + --> $DIR/empty-attributes.rs:14:1 + | +LL | #![forbid()] + | ^^^^^^^^^^^^ help: remove this attribute + | + = note: attribute `forbid` with an empty list has no effect + +error: unused attribute + --> $DIR/empty-attributes.rs:2:1 + | +LL | #![allow()] + | ^^^^^^^^^^^ help: remove this attribute + | + = note: attribute `allow` with an empty list has no effect + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error: unused attribute --> $DIR/empty-attributes.rs:5:1 | +LL | #![expect()] + | ^^^^^^^^^^^^ help: remove this attribute + | + = note: attribute `expect` with an empty list has no effect + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: unused attribute + --> $DIR/empty-attributes.rs:8:1 + | +LL | #![warn()] + | ^^^^^^^^^^ help: remove this attribute + | + = note: attribute `warn` with an empty list has no effect + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: unused attribute + --> $DIR/empty-attributes.rs:11:1 + | LL | #![deny()] | ^^^^^^^^^^ help: remove this attribute | = note: attribute `deny` with an empty list has no effect + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: unused attribute - --> $DIR/empty-attributes.rs:6:1 + --> $DIR/empty-attributes.rs:14:1 | LL | #![forbid()] | ^^^^^^^^^^^^ help: remove this attribute | = note: attribute `forbid` with an empty list has no effect + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: unused attribute - --> $DIR/empty-attributes.rs:7:1 + --> $DIR/empty-attributes.rs:17:1 | LL | #![feature()] | ^^^^^^^^^^^^^ help: remove this attribute @@ -52,7 +97,7 @@ LL | #![feature()] = note: using `feature` with an empty list has no effect error: unused attribute - --> $DIR/empty-attributes.rs:9:1 + --> $DIR/empty-attributes.rs:19:1 | LL | #[repr()] | ^^^^^^^^^ help: remove this attribute @@ -60,12 +105,12 @@ LL | #[repr()] = note: using `repr` with an empty list has no effect error: unused attribute - --> $DIR/empty-attributes.rs:12:1 + --> $DIR/empty-attributes.rs:22:1 | LL | #[target_feature()] | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute | = note: using `target_feature` with an empty list has no effect -error: aborting due to 8 previous errors +error: aborting due to 13 previous errors diff --git a/tests/ui/tool-attributes/cross-crate.stderr b/tests/ui/tool-attributes/cross-crate.stderr index 051a1b05405e9..b2be2b83c13f4 100644 --- a/tests/ui/tool-attributes/cross-crate.stderr +++ b/tests/ui/tool-attributes/cross-crate.stderr @@ -2,7 +2,7 @@ error[E0710]: unknown tool name `foo` found in scoped lint: `foo::baz` --> $DIR/cross-crate.rs:7:9 | LL | #[allow(foo::baz)] - | ^^^ + | ^^^^^^^^ | = help: add `#![register_tool(foo)]` to the crate root @@ -16,7 +16,7 @@ error[E0710]: unknown tool name `foo` found in scoped lint: `foo::baz` --> $DIR/cross-crate.rs:7:9 | LL | #[allow(foo::baz)] - | ^^^ + | ^^^^^^^^ | = help: add `#![register_tool(foo)]` to the crate root = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -25,7 +25,7 @@ error[E0710]: unknown tool name `foo` found in scoped lint: `foo::baz` --> $DIR/cross-crate.rs:7:9 | LL | #[allow(foo::baz)] - | ^^^ + | ^^^^^^^^ | = help: add `#![register_tool(foo)]` to the crate root = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/tool-attributes/tool_lints.stderr b/tests/ui/tool-attributes/tool_lints.stderr index eee0a9784ece8..cb42e17134476 100644 --- a/tests/ui/tool-attributes/tool_lints.stderr +++ b/tests/ui/tool-attributes/tool_lints.stderr @@ -2,7 +2,7 @@ error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar` --> $DIR/tool_lints.rs:1:8 | LL | #[warn(foo::bar)] - | ^^^ + | ^^^^^^^^ | = help: add `#![register_tool(foo)]` to the crate root @@ -10,7 +10,7 @@ error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar` --> $DIR/tool_lints.rs:1:8 | LL | #[warn(foo::bar)] - | ^^^ + | ^^^^^^^^ | = help: add `#![register_tool(foo)]` to the crate root = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -19,7 +19,7 @@ error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar` --> $DIR/tool_lints.rs:1:8 | LL | #[warn(foo::bar)] - | ^^^ + | ^^^^^^^^ | = help: add `#![register_tool(foo)]` to the crate root = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/tool-attributes/unknown-lint-tool-name.stderr b/tests/ui/tool-attributes/unknown-lint-tool-name.stderr index 91baf88273756..49044c62a7f6a 100644 --- a/tests/ui/tool-attributes/unknown-lint-tool-name.stderr +++ b/tests/ui/tool-attributes/unknown-lint-tool-name.stderr @@ -2,7 +2,7 @@ error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar` --> $DIR/unknown-lint-tool-name.rs:1:9 | LL | #![deny(foo::bar)] - | ^^^ + | ^^^^^^^^ | = help: add `#![register_tool(foo)]` to the crate root @@ -10,7 +10,7 @@ error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar` --> $DIR/unknown-lint-tool-name.rs:5:9 | LL | #[allow(foo::bar)] - | ^^^ + | ^^^^^^^^ | = help: add `#![register_tool(foo)]` to the crate root @@ -18,7 +18,7 @@ error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar` --> $DIR/unknown-lint-tool-name.rs:1:9 | LL | #![deny(foo::bar)] - | ^^^ + | ^^^^^^^^ | = help: add `#![register_tool(foo)]` to the crate root = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -27,7 +27,7 @@ error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar` --> $DIR/unknown-lint-tool-name.rs:5:9 | LL | #[allow(foo::bar)] - | ^^^ + | ^^^^^^^^ | = help: add `#![register_tool(foo)]` to the crate root = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -36,7 +36,7 @@ error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar` --> $DIR/unknown-lint-tool-name.rs:1:9 | LL | #![deny(foo::bar)] - | ^^^ + | ^^^^^^^^ | = help: add `#![register_tool(foo)]` to the crate root = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -45,7 +45,7 @@ error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar` --> $DIR/unknown-lint-tool-name.rs:5:9 | LL | #[allow(foo::bar)] - | ^^^ + | ^^^^^^^^ | = help: add `#![register_tool(foo)]` to the crate root = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/unpretty/exhaustive.expanded.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout index 6dd7b4c5e1f3a..7eca271aeda13 100644 --- a/tests/ui/unpretty/exhaustive.expanded.stdout +++ b/tests/ui/unpretty/exhaustive.expanded.stdout @@ -28,7 +28,7 @@ #![feature(try_blocks)] #![feature(try_blocks_heterogeneous)] #![feature(yeet_expr)] -#![allow(incomplete_features)] +#![allow(incomplete_features, unused_attributes)] extern crate std; #[prelude_import] use std::prelude::rust_2024::*; diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 1b18e00c951c8..3bf26a63f3b81 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -1,3 +1,14 @@ +#![attr = Feature([auto_traits#0, builtin_syntax#0, const_trait_impl#0, +coroutines#0, decl_macro#0, deref_patterns#0, explicit_tail_calls#0, +gen_blocks#0, more_qualified_paths#0, never_patterns#0, pattern_types#0, +pattern_type_macro#0, prelude_import#0, specialization#0, trace_macros#0, +trait_alias#0, try_blocks#0, try_blocks_heterogeneous#0, yeet_expr#0])] +#![attr = LintCheck([LintCheck {name: ["incomplete_features"], attr_index: 0, +lint_index: 0, kind: Allow}, LintCheck {name: ["unused_attributes"], +attr_index: 0, lint_index: 1, kind: Allow}])] +extern crate std; +#[attr = PreludeImport] +use std::prelude::rust_2024::*; //@ revisions: expanded hir //@[expanded]compile-flags: -Zunpretty=expanded //@[expanded]check-pass @@ -8,15 +19,6 @@ // Note: the HIR revision includes a `.stderr` file because there are some // errors that only occur once we get past the AST. -#![allow(incomplete_features)] -#![attr = Feature([auto_traits#0, builtin_syntax#0, const_trait_impl#0, -coroutines#0, decl_macro#0, deref_patterns#0, explicit_tail_calls#0, -gen_blocks#0, more_qualified_paths#0, never_patterns#0, pattern_types#0, -pattern_type_macro#0, prelude_import#0, specialization#0, trace_macros#0, -trait_alias#0, try_blocks#0, try_blocks_heterogeneous#0, yeet_expr#0])] -extern crate std; -#[attr = PreludeImport] -use std::prelude::rust_2024::*; mod prelude { use std::prelude::rust_2024::*; @@ -38,7 +40,9 @@ use self::prelude::*; * inner multi-line doc comment */ #[doc = "inner doc attribute"] -#[allow(dead_code, unused_variables)] +#[attr = LintCheck([LintCheck {name: ["dead_code"], attr_index: 0, +lint_index: 0, kind: Allow}, LintCheck {name: ["unused_variables"], +attr_index: 0, lint_index: 1, kind: Allow}])] #[attr = NoStd] mod attributes { @@ -48,7 +52,6 @@ mod attributes { */ #[doc = "outer doc attribute"] #[doc = "macro"] - #[allow()] #[attr = Repr {reprs: [ReprC]}] struct Struct; } @@ -207,15 +210,7 @@ mod expressions { } /// ExprKind::Block - fn expr_block() { - { } - unsafe { } - 'a: { } - #[allow()] - { } - #[allow()] - { } - } + fn expr_block() { { } unsafe { } 'a: { } { } { } } /// ExprKind::Gen fn expr_gen() { @@ -243,9 +238,17 @@ mod expressions { type_ascribe!({ from_output(()) }, Option<_>); type_ascribe!({ from_output(match branch(None) { - Break { 0: residual } => #[allow(unreachable_code)] + Break { 0: residual } => + #[attr = LintCheck([LintCheck {name: ["unreachable_code"], + attr_index: 0, + lint_index: 0, + kind: Allow}])] break from_residual(residual), - Continue { 0: val } => #[allow(unreachable_code)] + Continue { 0: val } => + #[attr = LintCheck([LintCheck {name: ["unreachable_code"], + attr_index: 0, + lint_index: 0, + kind: Allow}])] val, }) }, Option) @@ -367,9 +370,17 @@ mod expressions { fn expr_try() { let expr; match branch(expr) { - Break { 0: residual } => #[allow(unreachable_code)] + Break { 0: residual } => + #[attr = LintCheck([LintCheck {name: ["unreachable_code"], + attr_index: 0, + lint_index: 0, + kind: Allow}])] return from_residual(residual), - Continue { 0: val } => #[allow(unreachable_code)] + Continue { 0: val } => + #[attr = LintCheck([LintCheck {name: ["unreachable_code"], + attr_index: 0, + lint_index: 0, + kind: Allow}])] val, }; } diff --git a/tests/ui/unpretty/exhaustive.rs b/tests/ui/unpretty/exhaustive.rs index 62a8b6b9ecc20..03ef63874ac0a 100644 --- a/tests/ui/unpretty/exhaustive.rs +++ b/tests/ui/unpretty/exhaustive.rs @@ -27,7 +27,7 @@ #![feature(try_blocks)] #![feature(try_blocks_heterogeneous)] #![feature(yeet_expr)] -#![allow(incomplete_features)] +#![allow(incomplete_features, unused_attributes)] mod prelude { pub use std::prelude::rust_2024::*; diff --git a/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout index 974ffd3b9c4e1..0600180f0c16a 100644 --- a/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout +++ b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout @@ -1,13 +1,14 @@ -//@ compile-flags: -Zunpretty=hir -//@ check-pass - -#![expect(incomplete_features)] -#![allow(dead_code)] #![attr = Feature([min_generic_const_args#0, macroless_generic_const_args#0, adt_const_params#0])] +#![attr = LintCheck([LintCheck {name: ["incomplete_features"], attr_index: 0, +lint_index: 0, kind: Expect}, LintCheck {name: ["dead_code"], attr_index: 1, +lint_index: 0, kind: Allow}])] extern crate std; #[attr = PreludeImport] use ::std::prelude::rust_2015::*; +//@ compile-flags: -Zunpretty=hir +//@ check-pass + use std::marker::ConstParamTy; diff --git a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout index 19bfe92e3b27f..e5816aef65c9b 100644 --- a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout +++ b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout @@ -1,3 +1,8 @@ +#![attr = LintCheck([LintCheck {name: ["dead_code"], attr_index: 0, +lint_index: 0, kind: Allow}])] +extern crate std; +#[attr = PreludeImport] +use ::std::prelude::rust_2015::*; // Regression test for the ICE described in #82328. The pretty-printer for // `-Zunpretty=hir,typed` would previously retrieve type-checking results // when entering a body, which means that type information was not available @@ -7,10 +12,6 @@ //@ check-pass //@ compile-flags: -Zunpretty=hir,typed //@ edition: 2015 -#![allow(dead_code)] -extern crate std; -#[attr = PreludeImport] -use ::std::prelude::rust_2015::*; fn main() ({ } as ()) diff --git a/tests/ui/where-clauses/unsupported_attribute.rs b/tests/ui/where-clauses/unsupported_attribute.rs index e86274f3ed5e7..505c42f127390 100644 --- a/tests/ui/where-clauses/unsupported_attribute.rs +++ b/tests/ui/where-clauses/unsupported_attribute.rs @@ -18,8 +18,8 @@ where #[should_panic] 'a: 'static, //~ ERROR attribute cannot be used on #[macro_use] T: Trait, //~ ERROR attribute cannot be used on #[macro_use] 'a: 'static, //~ ERROR attribute cannot be used on - #[allow(unused)] T: Trait, //~ ERROR most attributes are not supported in `where` clauses - #[allow(unused)] 'a: 'static, //~ ERROR most attributes are not supported in `where` clauses + #[allow(unused)] T: Trait, //~ ERROR the `allow` attribute cannot be used on where predicates + #[allow(unused)] 'a: 'static, //~ ERROR the `allow` attribute cannot be used on where predicates #[deprecated] T: Trait, //~ ERROR attribute cannot be used on #[deprecated] 'a: 'static, //~ ERROR attribute cannot be used on #[automatically_derived] T: Trait, //~ ERROR attribute cannot be used on diff --git a/tests/ui/where-clauses/unsupported_attribute.stderr b/tests/ui/where-clauses/unsupported_attribute.stderr index 94f9719365c6e..678bbd813aaaa 100644 --- a/tests/ui/where-clauses/unsupported_attribute.stderr +++ b/tests/ui/where-clauses/unsupported_attribute.stderr @@ -74,21 +74,21 @@ LL | #[macro_use] 'a: 'static, | = help: the `macro_use` attribute can be applied to extern crates and modules -error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:21:5 +error: the `allow` attribute cannot be used on where predicates + --> $DIR/unsupported_attribute.rs:21:7 | LL | #[allow(unused)] T: Trait, - | ^^^^^^^^^^^^^^^^ + | ^^^^^ | - = help: only `#[cfg]` and `#[cfg_attr]` are supported + = help: the `allow` attribute can be applied to associated consts, associated types, break expressions, const parameters, constants, crates, data types, enum variants, extern crates, for loops, foreign modules, foreign statics, function params, functions, global asms, impl blocks, lifetime parameters, loops, macro defs, match arms, modules, pattern fields, statics, struct fields, trait aliases, traits, type aliases, type parameters, use statements, and while loops -error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:22:5 +error: the `allow` attribute cannot be used on where predicates + --> $DIR/unsupported_attribute.rs:22:7 | LL | #[allow(unused)] 'a: 'static, - | ^^^^^^^^^^^^^^^^ + | ^^^^^ | - = help: only `#[cfg]` and `#[cfg_attr]` are supported + = help: the `allow` attribute can be applied to associated consts, associated types, break expressions, const parameters, constants, crates, data types, enum variants, extern crates, for loops, foreign modules, foreign statics, function params, functions, global asms, impl blocks, lifetime parameters, loops, macro defs, match arms, modules, pattern fields, statics, struct fields, trait aliases, traits, type aliases, type parameters, use statements, and while loops error: the `deprecated` attribute cannot be used on where predicates --> $DIR/unsupported_attribute.rs:23:7