From 8e25d89b5f40d4b9e6c837cec4d8c3e6c4fedc05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Thu, 6 Feb 2025 16:02:11 +0100 Subject: [PATCH 1/7] implement inline parser --- compiler/rustc_attr_data_structures/src/attributes.rs | 3 ++- compiler/rustc_attr_parsing/src/attributes/inline.rs | 2 +- compiler/rustc_attr_parsing/src/attributes/mod.rs | 1 + compiler/rustc_attr_parsing/src/context.rs | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 845e4d5e5d0fa..439ed7179d96e 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -8,7 +8,7 @@ use thin_vec::ThinVec; use crate::{DefaultBodyStability, PartialConstStability, PrintAttribute, RustcVersion, Stability}; -#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)] pub enum InlineAttr { None, Hint, @@ -189,6 +189,7 @@ pub enum AttributeKind { DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol }, /// Represents `#[rustc_macro_transparency]`. + Inline(InlineAttr, Span), MacroTransparency(Transparency), /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index c7f82082c2eec..3056706df374f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -63,7 +63,7 @@ impl SingleAttributeParser for RustcForceInlineParser { const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(Word, List: "reason", NameValueStr: "reason"); - fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { let reason = match args { ArgParser::NoArgs => None, ArgParser::List(list) => { diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index caf55e6685efc..ef4dc665ea2f0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -29,6 +29,7 @@ pub(crate) mod allow_unstable; pub(crate) mod cfg; pub(crate) mod confusables; pub(crate) mod deprecation; +pub(crate) mod inline; pub(crate) mod repr; pub(crate) mod stability; pub(crate) mod transparency; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 47f72232828ee..8452096149535 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -18,6 +18,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; +use crate::attributes::inline::InlineParser; use crate::attributes::repr::ReprParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, @@ -104,6 +105,7 @@ attribute_parsers!( // tidy-alphabetical-start Single, Single, + Single, Single, // tidy-alphabetical-end ]; From 8cd5a98451f80f4fa6b3e2d933255283bea808ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 7 Mar 2025 16:06:58 +0100 Subject: [PATCH 2/7] implement rustc_force_inline parser --- compiler/rustc_attr_data_structures/src/attributes.rs | 3 ++- compiler/rustc_attr_parsing/src/attributes/inline.rs | 1 + compiler/rustc_attr_parsing/src/context.rs | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 439ed7179d96e..f51dc5a54a202 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -194,7 +194,8 @@ pub enum AttributeKind { /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr(ThinVec<(ReprAttr, Span)>), - + /// Represents `#[rustc_force_inline]` + RustcForceInline(Span, Option), /// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`. Stability { stability: Stability, diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index 3056706df374f..fecddde930a8d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -11,6 +11,7 @@ use super::{AcceptContext, AttributeOrder, OnDuplicate}; use crate::attributes::SingleAttributeParser; use crate::context::Stage; use crate::parser::ArgParser; +use crate::session_diagnostics::IncorrectMetaItem; pub(crate) struct InlineParser; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 8452096149535..3aaecc187b0f9 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -18,7 +18,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; -use crate::attributes::inline::InlineParser; +use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; use crate::attributes::repr::ReprParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, @@ -106,6 +106,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, // tidy-alphabetical-end ]; From 8b2d6f7efaaa3d2a4ae22887e1b8f28b59349aac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 7 Mar 2025 16:08:13 +0100 Subject: [PATCH 3/7] convert entire codebase to parsed inline attrs --- .../src/attributes.rs | 12 ++- .../rustc_codegen_ssa/src/codegen_attrs.rs | 53 ++------- compiler/rustc_passes/src/check_attr.rs | 102 ++++++++++-------- .../clippy_lints/src/attrs/inline_always.rs | 25 ++--- .../src/inline_fn_without_body.rs | 12 ++- .../clippy/clippy_lints/src/missing_inline.rs | 6 +- .../clippy_lints/src/pass_by_ref_or_value.rs | 14 +-- 7 files changed, 105 insertions(+), 119 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index f51dc5a54a202..eb8f857845f6f 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -183,10 +183,18 @@ pub enum AttributeKind { ConstStabilityIndirect, /// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute). - Deprecation { deprecation: Deprecation, span: Span }, + Deprecation { + deprecation: Deprecation, + span: Span, + }, /// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html). - DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol }, + DocComment { + style: AttrStyle, + kind: CommentKind, + span: Span, + comment: Symbol, + }, /// Represents `#[rustc_macro_transparency]`. Inline(InlineAttr, Span), diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 0b31fa8fa886b..8388fd267f587 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,10 +1,14 @@ use std::str::FromStr; use rustc_abi::ExternAbi; -use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; +use rustc_ast::expand::autodiff_attrs::{ + AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity, +}; use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr}; use rustc_attr_data_structures::ReprAttr::ReprAlign; -use rustc_attr_data_structures::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr}; +use rustc_attr_data_structures::{ + AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, find_attr, +}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; @@ -21,7 +25,6 @@ use rustc_session::parse::feature_err; use rustc_session::{Session, lint}; use rustc_span::{Ident, Span, sym}; use rustc_target::spec::SanitizerSet; -use tracing::debug; use crate::errors; use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature_attr}; @@ -449,48 +452,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx); - codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { - if !attr.has_name(sym::inline) { - return ia; - } - - if attr.is_word() { - return InlineAttr::Hint; - } - let Some(ref items) = attr.meta_item_list() else { - return ia; - }; - inline_span = Some(attr.span()); - - let [item] = &items[..] else { - tcx.dcx().emit_err(errors::ExpectedOneArgument { span: attr.span() }); - return InlineAttr::None; - }; - - if item.has_name(sym::always) { - InlineAttr::Always - } else if item.has_name(sym::never) { - InlineAttr::Never - } else { - tcx.dcx().emit_err(errors::InvalidArgument { span: items[0].span() }); - - InlineAttr::None - } - }); - codegen_fn_attrs.inline = attrs.iter().fold(codegen_fn_attrs.inline, |ia, attr| { - if !attr.has_name(sym::rustc_force_inline) || !tcx.features().rustc_attrs() { - return ia; - } - - if attr.is_word() { - InlineAttr::Force { attr_span: attr.span(), reason: None } - } else if let Some(val) = attr.value_str() { - InlineAttr::Force { attr_span: attr.span(), reason: Some(val) } - } else { - debug!("`rustc_force_inline` not checked by attribute validation"); - ia - } - }); + codegen_fn_attrs.inline = + find_attr!(attrs, AttributeKind::Inline(i, _) => *i).unwrap_or(InlineAttr::None); // naked function MUST NOT be inlined! This attribute is required for the rust compiler itself, // but not for the code generation backend because at that point the naked function will just be diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4e2be8ff0b817..737f1e31fca9b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,7 +10,7 @@ use std::collections::hash_map::Entry; use rustc_abi::{Align, ExternAbi, Size}; use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast}; -use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr}; +use rustc_attr_data_structures::{AttributeKind, InlineAttr, ReprAttr, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; @@ -124,6 +124,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::Stability { span, .. } | AttributeKind::ConstStability { span, .. }, ) => self.check_stability_promotable(*span, target), + Attribute::Parsed(AttributeKind::Inline(kind, attr_span)) => { + self.check_inline(hir_id, *attr_span, span, kind, target) + } Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self .check_allow_internal_unstable( hir_id, @@ -155,7 +158,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::diagnostic, sym::on_unimplemented, ..] => { self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target) } - [sym::inline, ..] => self.check_inline(hir_id, attr, span, target), [sym::coverage, ..] => self.check_coverage(attr, span, target), [sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target), [sym::no_sanitize, ..] => { @@ -367,11 +369,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_rustc_force_inline(hir_id, attrs, span, target); } - fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) { + fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr_span: Span, sym: &str) { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::IgnoredAttrWithMacro { sym }, ); } @@ -431,7 +433,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if an `#[inline]` is applied to a function or a closure. - fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_inline( + &self, + hir_id: HirId, + attr_span: Span, + defn_span: Span, + kind: &InlineAttr, + target: Target, + ) { match target { Target::Fn | Target::Closure @@ -440,7 +449,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::IgnoredInlineAttrFnProto, ) } @@ -451,25 +460,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Target::AssocConst => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::IgnoredInlineAttrConstants, ), // FIXME(#80564): Same for fields, arms, and macro defs Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "inline") + self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "inline") } _ => { - self.dcx().emit_err(errors::InlineNotFnOrClosure { - attr_span: attr.span(), - defn_span: span, - }); + self.dcx().emit_err(errors::InlineNotFnOrClosure { attr_span, defn_span }); } } // `#[inline]` is ignored if the symbol must be codegened upstream because it's exported. if let Some(did) = hir_id.as_owner() && self.tcx.def_kind(did).has_codegen_attrs() - && !matches!(attr.meta_item_list().as_deref(), Some([item]) if item.has_name(sym::never)) + && kind != &InlineAttr::Never { let attrs = self.tcx.codegen_fn_attrs(did); // Not checking naked as `#[inline]` is forbidden for naked functions anyways. @@ -477,7 +483,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::InlineIgnoredForExported {}, ); } @@ -711,6 +717,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } } + // FIXME(#80564): We permit struct fields, match arms and macro defs to have an + // `#[naked]` attribute with just a lint, because we previously + // erroneously allowed it and some crates used it accidentally, to be compatible + // with crates depending on them, we can't throw an error here. + Target::Field | Target::Arm | Target::MacroDef => { + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "naked") + } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { attr_span: attr.span(), @@ -787,7 +800,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { for attr in attrs { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "track_caller"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "track_caller"); } } _ => { @@ -830,7 +843,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "non_exhaustive"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "non_exhaustive"); } _ => { self.dcx().emit_err(errors::NonExhaustiveWrongLocation { @@ -850,7 +863,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "marker"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "marker"); } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { @@ -904,7 +917,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "target_feature"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "target_feature"); } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { @@ -1619,7 +1632,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "cold"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "cold"); } _ => { // FIXME: #[cold] was previously allowed on non-functions and some crates used @@ -1661,7 +1674,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_name"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_name"); } _ => { // FIXME: #[cold] was previously allowed on non-functions/statics and some crates @@ -1695,7 +1708,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "no_link"); } _ => { self.dcx().emit_err(errors::NoLink { attr_span: attr.span(), span }); @@ -1717,7 +1730,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "export_name"); } _ => { self.dcx().emit_err(errors::ExportName { attr_span: attr.span(), span }); @@ -1891,7 +1904,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_section"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_section"); } _ => { // FIXME: #[link_section] was previously allowed on non-functions/statics and some @@ -1916,7 +1929,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_mangle"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "no_mangle"); } // FIXME: #[no_mangle] was previously allowed on non-functions/statics, this should be an error // The error should specify that the item that is wrong is specifically a *foreign* fn/static @@ -2263,9 +2276,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // `#[allow_internal_unstable]` attribute with just a lint, because we previously // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "allow_internal_unstable") - } + Target::Field | Target::Arm | Target::MacroDef => self + .inline_attr_str_error_with_macro_def( + hir_id, + attr.span(), + "allow_internal_unstable", + ), _ => { self.tcx .dcx() @@ -2638,8 +2654,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { span: Span, target: Target, ) { - let force_inline_attr = attrs.iter().find(|attr| attr.has_name(sym::rustc_force_inline)); - match (target, force_inline_attr) { + match ( + target, + find_attr!(attrs, AttributeKind::Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span), + ) { (Target::Closure, None) => { let is_coro = matches!( self.tcx.hir_expect_expr(hir_id).kind, @@ -2651,20 +2669,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ); let parent_did = self.tcx.hir_get_parent_item(hir_id).to_def_id(); let parent_span = self.tcx.def_span(parent_did); - let parent_force_inline_attr = - self.tcx.get_attr(parent_did, sym::rustc_force_inline); - if let Some(attr) = parent_force_inline_attr - && is_coro + + if let Some(attr_span) = find_attr!( + self.tcx.get_all_attrs(parent_did), + AttributeKind::Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span + ) && is_coro { - self.dcx().emit_err(errors::RustcForceInlineCoro { - attr_span: attr.span(), - span: parent_span, - }); + self.dcx() + .emit_err(errors::RustcForceInlineCoro { attr_span, span: parent_span }); } } (Target::Fn, _) => (), - (_, Some(attr)) => { - self.dcx().emit_err(errors::RustcForceInline { attr_span: attr.span(), span }); + (_, Some(attr_span)) => { + self.dcx().emit_err(errors::RustcForceInline { attr_span, span }); } (_, None) => (), } @@ -2885,10 +2902,8 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) { let attrs = tcx.hir_attrs(item.hir_id()); - for attr in attrs { - if attr.has_name(sym::inline) { - tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span: attr.span() }); - } + if let Some(attr_span) = find_attr!(attrs, AttributeKind::Inline(_, span) => *span) { + tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span }); } } @@ -2908,6 +2923,7 @@ pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { check_mod_attrs, ..*providers }; } +// FIXME(jdonszelmann): remove, check during parsing fn check_duplicates( tcx: TyCtxt<'_>, attr: &Attribute, diff --git a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs index cb63fadb4e21c..141ba7b0636a5 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs @@ -1,29 +1,22 @@ use super::INLINE_ALWAYS; -use super::utils::is_word; use clippy_utils::diagnostics::span_lint; +use rustc_attr_parsing::{find_attr, AttributeKind, InlineAttr}; use rustc_hir::Attribute; use rustc_lint::LateContext; use rustc_span::symbol::Symbol; -use rustc_span::{Span, sym}; +use rustc_span::Span; pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) { if span.from_expansion() { return; } - for attr in attrs { - if let Some(values) = attr.meta_item_list() { - if values.len() != 1 || !attr.has_name(sym::inline) { - continue; - } - if is_word(&values[0], sym::always) { - span_lint( - cx, - INLINE_ALWAYS, - attr.span(), - format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"), - ); - } - } + if let Some(span) = find_attr!(attrs, AttributeKind::Inline(InlineAttr::Always, span) => *span) { + span_lint( + cx, + INLINE_ALWAYS, + span, + format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"), + ); } } diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs index da5ca5e677218..23c427f3c20cd 100644 --- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs +++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::DiagExt; +use rustc_attr_parsing::{find_attr, AttributeKind}; use rustc_errors::Applicability; use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -32,15 +32,19 @@ declare_lint_pass!(InlineFnWithoutBody => [INLINE_FN_WITHOUT_BODY]); impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind - && let Some(attr) = cx.tcx.hir_attrs(item.hir_id()).iter().find(|a| a.has_name(sym::inline)) + && let Some(attr_span) = find_attr!(cx + .tcx + .hir_attrs(item.hir_id()), + AttributeKind::Inline(_, span) => *span + ) { span_lint_and_then( cx, INLINE_FN_WITHOUT_BODY, - attr.span(), + attr_span, format!("use of `#[inline]` on trait method `{}` which has no body", item.ident), |diag| { - diag.suggest_remove_item(cx, attr.span(), "remove", Applicability::MachineApplicable); + diag.suggest_remove_item(cx, attr_span, "remove", Applicability::MachineApplicable); }, ); } diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index 1f613171b46e8..25579c10cb97c 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::span_lint; +use rustc_attr_parsing::{find_attr, AttributeKind}; use rustc_hir as hir; use rustc_hir::Attribute; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::AssocItemContainer; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -64,8 +65,7 @@ declare_clippy_lint! { } fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[Attribute], sp: Span, desc: &'static str) { - let has_inline = attrs.iter().any(|a| a.has_name(sym::inline)); - if !has_inline { + if !find_attr!(attrs, AttributeKind::Inline(..)) { span_lint( cx, MISSING_INLINE_IN_PUBLIC_ITEMS, diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index dadf49b64e517..dc86143b10e2f 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -3,10 +3,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy}; use clippy_utils::{is_self, is_self_ty}; +use rustc_attr_parsing::{find_attr, AttributeKind, InlineAttr}; +use rustc_data_structures::fx::FxHashSet; use core::ops::ControlFlow; use rustc_abi::ExternAbi; -use rustc_ast::attr; -use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; @@ -270,11 +270,13 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue { return; } let attrs = cx.tcx.hir_attrs(hir_id); + if find_attr!(attrs, AttributeKind::Inline(InlineAttr::Always, _)) { + return; + } + for a in attrs { - if let Some(meta_items) = a.meta_item_list() - && (a.has_name(sym::proc_macro_derive) - || (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always))) - { + // FIXME(jdonszelmann): make part of the find_attr above + if a.has_name(sym::proc_macro_derive) { return; } } From 3b7ae9a72113b79d2503d78f2f0aeae78ae5ef5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 4 Mar 2025 14:17:06 +0100 Subject: [PATCH 4/7] fix bugs in inline/force_inline and diagnostics of all attr parsers --- .../src/attributes.rs | 2 - .../rustc_attr_data_structures/src/lints.rs | 1 + compiler/rustc_attr_parsing/messages.ftl | 5 + .../src/attributes/allow_unstable.rs | 3 + .../src/attributes/confusables.rs | 63 ++++---- .../src/attributes/deprecation.rs | 6 + .../src/attributes/inline.rs | 3 +- .../rustc_attr_parsing/src/attributes/mod.rs | 25 +++- .../rustc_attr_parsing/src/attributes/repr.rs | 3 + .../src/attributes/stability.rs | 70 +++++---- .../src/attributes/transparency.rs | 3 + compiler/rustc_attr_parsing/src/context.rs | 96 ++++++++++--- compiler/rustc_attr_parsing/src/lints.rs | 15 +- .../src/session_diagnostics.rs | 83 ++++++++++- .../rustc_codegen_ssa/src/codegen_attrs.rs | 16 ++- compiler/rustc_feature/src/builtin_attrs.rs | 40 ++++-- compiler/rustc_lint/src/lints.rs | 1 + compiler/rustc_parse/src/validate_attr.rs | 10 +- compiler/rustc_passes/src/check_attr.rs | 14 +- tests/ui/attributes/multiple-invalid.stderr | 18 +-- tests/ui/error-codes/E0534.rs | 2 +- tests/ui/error-codes/E0534.stderr | 17 ++- ...43106-gating-of-builtin-attrs-error.stderr | 2 +- tests/ui/force-inlining/invalid.rs | 1 - tests/ui/force-inlining/invalid.stderr | 134 ++++++++++-------- tests/ui/invalid/invalid-inline.rs | 4 +- tests/ui/invalid/invalid-inline.stderr | 33 ++++- tests/ui/issues/issue-43988.rs | 4 +- tests/ui/issues/issue-43988.stderr | 58 +++++--- .../lint/unused/unused-attr-duplicate.stderr | 36 ++--- .../genercs-in-path-with-prettry-hir.stdout | 2 +- .../ui/malformed/malformed-regressions.stderr | 18 +-- tests/ui/span/E0535.rs | 2 +- tests/ui/span/E0535.stderr | 18 ++- 34 files changed, 569 insertions(+), 239 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index eb8f857845f6f..1688d378feec1 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -202,8 +202,6 @@ pub enum AttributeKind { /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr(ThinVec<(ReprAttr, Span)>), - /// Represents `#[rustc_force_inline]` - RustcForceInline(Span, Option), /// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`. Stability { stability: Stability, diff --git a/compiler/rustc_attr_data_structures/src/lints.rs b/compiler/rustc_attr_data_structures/src/lints.rs index 7e3664b2263b4..e34c54c6d323f 100644 --- a/compiler/rustc_attr_data_structures/src/lints.rs +++ b/compiler/rustc_attr_data_structures/src/lints.rs @@ -11,4 +11,5 @@ pub struct AttributeLint { #[derive(Clone, Debug, HashStable_Generic)] pub enum AttributeLintKind { UnusedDuplicate { this: Span, other: Span, warning: bool }, + IllFormedAttributeInput { suggestions: Vec }, } diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index c9443feb021bb..2687bfdc7168e 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -23,6 +23,10 @@ attr_parsing_expects_feature_list = attr_parsing_expects_features = `{$name}` expects feature names +attr_parsing_ill_formed_attribute_input = {$num_suggestions -> + [1] attribute must be of the form {$suggestions} + *[other] valid forms for the attribute are {$suggestions} + } attr_parsing_incorrect_meta_item = expected a quoted string literal attr_parsing_incorrect_meta_item_suggestion = consider surrounding this with quotes @@ -136,6 +140,7 @@ attr_parsing_unused_duplicate = .suggestion = remove this attribute .note = attribute also specified here .warn = {-passes_previously_accepted} + attr_parsing_unused_multiple = multiple `{$name}` attributes .suggestion = remove this attribute diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 81192f902a232..21b01a8d071bf 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -1,6 +1,7 @@ use std::iter; use rustc_attr_data_structures::AttributeKind; +use rustc_feature::{AttributeTemplate, template}; use rustc_span::{Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; @@ -13,6 +14,7 @@ impl CombineAttributeParser for AllowInternalUnstableParser { const PATH: &[Symbol] = &[sym::allow_internal_unstable]; type Item = (Symbol, Span); const CONVERT: ConvertFn = AttributeKind::AllowInternalUnstable; + const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ..."); fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, @@ -29,6 +31,7 @@ impl CombineAttributeParser for AllowConstFnUnstableParser { const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable]; type Item = Symbol; const CONVERT: ConvertFn = AttributeKind::AllowConstFnUnstable; + const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ..."); fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index afd3c012f05ad..0be9d690c32d3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -1,4 +1,5 @@ use rustc_attr_data_structures::AttributeKind; +use rustc_feature::template; use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; @@ -13,37 +14,41 @@ pub(crate) struct ConfusablesParser { } impl AttributeParser for ConfusablesParser { - const ATTRIBUTES: AcceptMapping = &[(&[sym::rustc_confusables], |this, cx, args| { - let Some(list) = args.list() else { - // FIXME(jdonszelmann): error when not a list? Bring validation code here. - // NOTE: currently subsequent attributes are silently ignored using - // tcx.get_attr(). - return; - }; - - if list.is_empty() { - cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span }); - } - - for param in list.mixed() { - let span = param.span(); - - let Some(lit) = param.lit() else { - cx.emit_err(session_diagnostics::IncorrectMetaItem { - span, - suggestion: Some(session_diagnostics::IncorrectMetaItemSuggestion { - lo: span.shrink_to_lo(), - hi: span.shrink_to_hi(), - }), - }); - continue; + const ATTRIBUTES: AcceptMapping = &[( + &[sym::rustc_confusables], + template!(List: r#""name1", "name2", ..."#), + |this, cx, args| { + let Some(list) = args.list() else { + // FIXME(jdonszelmann): error when not a list? Bring validation code here. + // NOTE: currently subsequent attributes are silently ignored using + // tcx.get_attr(). + return; }; - this.confusables.push(lit.symbol); - } - - this.first_span.get_or_insert(cx.attr_span); - })]; + if list.is_empty() { + cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span }); + } + + for param in list.mixed() { + let span = param.span(); + + let Some(lit) = param.lit() else { + cx.emit_err(session_diagnostics::IncorrectMetaItem { + span, + suggestion: Some(session_diagnostics::IncorrectMetaItemSuggestion { + lo: span.shrink_to_lo(), + hi: span.shrink_to_hi(), + }), + }); + continue; + }; + + this.confusables.push(lit.symbol); + } + + this.first_span.get_or_insert(cx.attr_span); + }, + )]; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { if self.confusables.is_empty() { diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 1faee41c2a9d6..692f587ba037e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -1,4 +1,5 @@ use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation}; +use rustc_feature::{AttributeTemplate, template}; use rustc_span::{Span, Symbol, sym}; use super::util::parse_version; @@ -45,6 +46,11 @@ impl SingleAttributeParser for DeprecationParser { const PATH: &[Symbol] = &[sym::deprecated]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = template!( + Word, + List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#, + NameValueStr: "reason" + ); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { let features = cx.features(); diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index fecddde930a8d..da56656e3ed34 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -11,7 +11,6 @@ use super::{AcceptContext, AttributeOrder, OnDuplicate}; use crate::attributes::SingleAttributeParser; use crate::context::Stage; use crate::parser::ArgParser; -use crate::session_diagnostics::IncorrectMetaItem; pub(crate) struct InlineParser; @@ -30,7 +29,7 @@ impl SingleAttributeParser for InlineParser { return None; }; - match l.meta_item().and_then(|i| i.word_without_args().map(|i| i.name)) { + match l.meta_item().and_then(|i| i.path().word().map(|i| i.name)) { Some(sym::always) => { Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span)) } diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index ef4dc665ea2f0..29269923735fb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -18,6 +18,7 @@ use std::marker::PhantomData; use rustc_attr_data_structures::AttributeKind; use rustc_attr_data_structures::lints::AttributeLintKind; +use rustc_feature::AttributeTemplate; use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; @@ -36,7 +37,7 @@ pub(crate) mod transparency; pub(crate) mod util; type AcceptFn = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>); -type AcceptMapping = &'static [(&'static [Symbol], AcceptFn)]; +type AcceptMapping = &'static [(&'static [Symbol], AttributeTemplate, AcceptFn)]; /// An [`AttributeParser`] is a type which searches for syntactic attributes. /// @@ -88,6 +89,9 @@ pub(crate) trait SingleAttributeParser: 'static { const ATTRIBUTE_ORDER: AttributeOrder; const ON_DUPLICATE: OnDuplicate; + /// The template this attribute parser should implement. Used for diagnostics. + const TEMPLATE: AttributeTemplate; + /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`] fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option; } @@ -104,8 +108,10 @@ impl, S: Stage> Default for Single { } impl, S: Stage> AttributeParser for Single { - const ATTRIBUTES: AcceptMapping = - &[(T::PATH, |group: &mut Single, cx, args| { + const ATTRIBUTES: AcceptMapping = &[( + T::PATH, + >::TEMPLATE, + |group: &mut Single, cx, args| { if let Some(pa) = T::convert(cx, args) { match T::ATTRIBUTE_ORDER { // keep the first and report immediately. ignore this attribute @@ -126,7 +132,8 @@ impl, S: Stage> AttributeParser for Single group.1 = Some((pa, cx.attr_span)); } - })]; + }, + )]; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { Some(self.1?.0) @@ -223,6 +230,9 @@ pub(crate) trait CombineAttributeParser: 'static { type Item; const CONVERT: ConvertFn; + /// The template this attribute parser should implement. Used for diagnostics. + const TEMPLATE: AttributeTemplate; + /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`] fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, @@ -242,8 +252,11 @@ impl, S: Stage> Default for Combine { } impl, S: Stage> AttributeParser for Combine { - const ATTRIBUTES: AcceptMapping = - &[(T::PATH, |group: &mut Combine, cx, args| group.1.extend(T::extend(cx, args)))]; + const ATTRIBUTES: AcceptMapping = &[( + T::PATH, + >::TEMPLATE, + |group: &mut Combine, cx, args| group.1.extend(T::extend(cx, args)), + )]; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) } diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 753b2366b410e..6fb618541e392 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -1,6 +1,7 @@ use rustc_abi::Align; use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr}; +use rustc_feature::{AttributeTemplate, template}; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; @@ -23,6 +24,8 @@ impl CombineAttributeParser for ReprParser { type Item = (ReprAttr, Span); const PATH: &[Symbol] = &[sym::repr]; const CONVERT: ConvertFn = AttributeKind::Repr; + // FIXME(jdonszelmann): never used + const TEMPLATE: AttributeTemplate = template!(List: "C"); fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 3cbadd4c7ec22..993ce134dca5f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -5,6 +5,7 @@ use rustc_attr_data_structures::{ StableSince, UnstableReason, VERSION_PLACEHOLDER, }; use rustc_errors::ErrorGuaranteed; +use rustc_feature::{AttributeTemplate, template}; use rustc_span::{Span, Symbol, sym}; use super::util::parse_version; @@ -43,26 +44,39 @@ impl StabilityParser { impl AttributeParser for StabilityParser { const ATTRIBUTES: AcceptMapping = &[ - (&[sym::stable], |this, cx, args| { - reject_outside_std!(cx); - if !this.check_duplicate(cx) - && let Some((feature, level)) = parse_stability(cx, args) - { - this.stability = Some((Stability { level, feature }, cx.attr_span)); - } - }), - (&[sym::unstable], |this, cx, args| { - reject_outside_std!(cx); - if !this.check_duplicate(cx) - && let Some((feature, level)) = parse_unstability(cx, args) - { - this.stability = Some((Stability { level, feature }, cx.attr_span)); - } - }), - (&[sym::rustc_allowed_through_unstable_modules], |this, cx, args| { - reject_outside_std!(cx); - this.allowed_through_unstable_modules = args.name_value().and_then(|i| i.value_as_str()) - }), + ( + &[sym::stable], + template!(List: r#"feature = "name", since = "version""#), + |this, cx, args| { + reject_outside_std!(cx); + if !this.check_duplicate(cx) + && let Some((feature, level)) = parse_stability(cx, args) + { + this.stability = Some((Stability { level, feature }, cx.attr_span)); + } + }, + ), + ( + &[sym::unstable], + template!(List: r#"feature = "name", reason = "...", issue = "N""#), + |this, cx, args| { + reject_outside_std!(cx); + if !this.check_duplicate(cx) + && let Some((feature, level)) = parse_unstability(cx, args) + { + this.stability = Some((Stability { level, feature }, cx.attr_span)); + } + }, + ), + ( + &[sym::rustc_allowed_through_unstable_modules], + template!(NameValueStr: "deprecation message"), + |this, cx, args| { + reject_outside_std!(cx); + this.allowed_through_unstable_modules = + args.name_value().and_then(|i| i.value_as_str()) + }, + ), ]; fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option { @@ -96,8 +110,10 @@ pub(crate) struct BodyStabilityParser { } impl AttributeParser for BodyStabilityParser { - const ATTRIBUTES: AcceptMapping = - &[(&[sym::rustc_default_body_unstable], |this, cx, args| { + const ATTRIBUTES: AcceptMapping = &[( + &[sym::rustc_default_body_unstable], + template!(List: r#"feature = "name", reason = "...", issue = "N""#), + |this, cx, args| { reject_outside_std!(cx); if this.stability.is_some() { cx.dcx() @@ -105,7 +121,8 @@ impl AttributeParser for BodyStabilityParser { } else if let Some((feature, level)) = parse_unstability(cx, args) { this.stability = Some((DefaultBodyStability { level, feature }, cx.attr_span)); } - })]; + }, + )]; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { let (stability, span) = self.stability?; @@ -120,6 +137,7 @@ impl SingleAttributeParser for ConstStabilityIndirectParser { const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; + const TEMPLATE: AttributeTemplate = template!(Word); fn convert(_cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option { Some(AttributeKind::ConstStabilityIndirect) @@ -146,7 +164,7 @@ impl ConstStabilityParser { impl AttributeParser for ConstStabilityParser { const ATTRIBUTES: AcceptMapping = &[ - (&[sym::rustc_const_stable], |this, cx, args| { + (&[sym::rustc_const_stable], template!(List: r#"feature = "name""#), |this, cx, args| { reject_outside_std!(cx); if !this.check_duplicate(cx) @@ -158,7 +176,7 @@ impl AttributeParser for ConstStabilityParser { )); } }), - (&[sym::rustc_const_unstable], |this, cx, args| { + (&[sym::rustc_const_unstable], template!(List: r#"feature = "name""#), |this, cx, args| { reject_outside_std!(cx); if !this.check_duplicate(cx) && let Some((feature, level)) = parse_unstability(cx, args) @@ -169,7 +187,7 @@ impl AttributeParser for ConstStabilityParser { )); } }), - (&[sym::rustc_promotable], |this, cx, _| { + (&[sym::rustc_promotable], template!(Word), |this, cx, _| { reject_outside_std!(cx); this.promotable = true; }), diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index 16ad9d03e500d..b0f5dac7fe249 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -1,4 +1,5 @@ use rustc_attr_data_structures::AttributeKind; +use rustc_feature::{AttributeTemplate, template}; use rustc_span::hygiene::Transparency; use rustc_span::{Symbol, sym}; @@ -17,6 +18,8 @@ impl SingleAttributeParser for TransparencyParser { const ON_DUPLICATE: OnDuplicate = OnDuplicate::Custom(|cx, used, unused| { cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes"); }); + const TEMPLATE: AttributeTemplate = + template!(NameValueStr: "transparent|semitransparent|opaque"); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { match args.name_value().and_then(|nv| nv.value_as_str()) { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 3aaecc187b0f9..ff0b8daec50ca 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -10,7 +10,7 @@ use rustc_ast::NodeId; use rustc_attr_data_structures::AttributeKind; use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind}; use rustc_errors::{DiagCtxtHandle, Diagnostic}; -use rustc_feature::Features; +use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId}; use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; @@ -26,11 +26,12 @@ use crate::attributes::stability::{ use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single}; use crate::parser::{ArgParser, MetaItemParser}; +use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason}; macro_rules! group_type { ($stage: ty) => { LazyLock<( - BTreeMap<&'static [Symbol], Box Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>>, + BTreeMap<&'static [Symbol], Vec<(AttributeTemplate, Box Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>)>>, Vec) -> Option>> )> }; @@ -59,7 +60,7 @@ macro_rules! attribute_parsers { @[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?]; ) => { pub(crate) static $name: group_type!($ty) = LazyLock::new(|| { - let mut accepts = BTreeMap::<_, Box Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>>::new(); + let mut accepts = BTreeMap::<_, Vec<(AttributeTemplate, Box Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>)>>::new(); let mut finalizes = Vec::) -> Option>>::new(); $( { @@ -67,13 +68,12 @@ macro_rules! attribute_parsers { static STATE_OBJECT: RefCell<$names> = RefCell::new(<$names>::default()); }; - for (k, v) in <$names>::ATTRIBUTES { - let old = accepts.insert(*k, Box::new(|cx, args| { + for (path, template, accept_fn) in <$names>::ATTRIBUTES { + accepts.entry(*path).or_default().push((*template, Box::new(|cx, args| { STATE_OBJECT.with_borrow_mut(|s| { - v(s, cx, args) + accept_fn(s, cx, args) }) - })); - assert!(old.is_none()); + }))); } finalizes.push(Box::new(|cx| { @@ -166,6 +166,14 @@ pub(crate) struct AcceptContext<'f, 'sess, S: Stage> { pub(crate) finalize_cx: FinalizeContext<'f, 'sess, S>, /// The span of the attribute currently being parsed pub(crate) attr_span: Span, + + /// The expected structure of the attribute. + /// + /// Used in reporting errors to give a hint to users what the attribute *should* look like. + pub(crate) template: &'f AttributeTemplate, + + /// The name of the attribute we're currently accepting. + pub(crate) attr_path: AttrPath, } impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { @@ -173,10 +181,54 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { S::emit_err(&self.sess, diag) } + /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing + /// must be delayed until after HIR is built. This method will take care of the details of + /// that. pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) { let id = self.target_id; (self.emit_lint)(AttributeLint { id, span, kind: lint }); } + + pub(crate) fn expected_string_literal(&self, span: Span) -> ErrorGuaranteed { + // 539? + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedStringLiteral, + }) + } + + // pub(crate) fn expected_any_arguments(&self, span: Span) -> ErrorGuaranteed { + // + // } + + pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed { + // E534? + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedSingleArgument, + }) + } + + pub(crate) fn expected_specific_argument( + &self, + span: Span, + options: Vec<&'static str>, + ) -> ErrorGuaranteed { + // E535? + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedSpecificArgument(options), + }) + } } impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> { @@ -375,18 +427,22 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { let args = parser.args(); let parts = path.segments().map(|i| i.name).collect::>(); - if let Some(accept) = S::parsers().0.get(parts.as_slice()) { - let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext { - finalize_cx: FinalizeContext { - cx: self, - target_span, - target_id, - emit_lint: &mut emit_lint, - }, - attr_span: lower_span(attr.span), - }; - - accept(&mut cx, args) + if let Some(accepts) = S::parsers().0.get(parts.as_slice()) { + for (template, accept) in accepts { + let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext { + finalize_cx: FinalizeContext { + cx: self, + target_span, + target_id, + emit_lint: &mut emit_lint, + }, + attr_span: lower_span(attr.span), + template, + attr_path: path.get_attribute_path(), + }; + + accept(&mut cx, args) + } } else { // If we're here, we must be compiling a tool attribute... Or someone // forgot to parse their fancy new attribute. Let's warn them in any case. diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index d0d112446b4d9..fee22293b473c 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -1,5 +1,5 @@ use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind}; -use rustc_errors::LintEmitter; +use rustc_errors::{DiagArgValue, LintEmitter}; use rustc_hir::HirId; use crate::session_diagnostics; @@ -15,5 +15,18 @@ pub fn emit_attribute_lint(lint: &AttributeLint, lint_emi *span, session_diagnostics::UnusedDuplicate { this, other, warning }, ), + AttributeLintKind::IllFormedAttributeInput { suggestions } => { + lint_emitter.emit_node_span_lint( + rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT, + *id, + *span, + session_diagnostics::IllFormedAttributeInput { + num_suggestions: suggestions.len(), + suggestions: DiagArgValue::StrListSepByAnd( + suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), + ), + }, + ); + } } } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 7f847d3dd4c5a..08cd8b5df2d69 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -2,7 +2,11 @@ use std::num::IntErrorKind; use rustc_ast as ast; use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; +use rustc_errors::{ + Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, +}; +use rustc_feature::AttributeTemplate; +use rustc_hir::AttrPath; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -462,6 +466,14 @@ pub(crate) struct UnusedDuplicate { pub warning: bool, } +// FIXME(jdonszelmann): duplicated in rustc_lints, should be moved here completely. +#[derive(LintDiagnostic)] +#[diag(attr_parsing_ill_formed_attribute_input)] +pub(crate) struct IllFormedAttributeInput { + pub num_suggestions: usize, + pub suggestions: DiagArgValue, +} + #[derive(Diagnostic)] #[diag(attr_parsing_stability_outside_std, code = E0734)] pub(crate) struct StabilityOutsideStd { @@ -490,3 +502,72 @@ pub(crate) struct UnrecognizedReprHint { #[primary_span] pub span: Span, } + +pub(crate) enum AttributeParseErrorReason { + ExpectedStringLiteral, + ExpectedSingleArgument, + ExpectedSpecificArgument(Vec<&'static str>), +} + +pub(crate) struct AttributeParseError { + pub(crate) span: Span, + pub(crate) attr_span: Span, + pub(crate) template: AttributeTemplate, + pub(crate) attribute: AttrPath, + pub(crate) reason: AttributeParseErrorReason, +} + +impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { + let name = self.attribute.to_string(); + + let mut diag = Diag::new(dcx, level, format!("malformed `{name}` attribute input")); + diag.span(self.attr_span); + diag.code(E0539); + match self.reason { + AttributeParseErrorReason::ExpectedStringLiteral => { + diag.span_note(self.span, "expected a string literal here"); + } + AttributeParseErrorReason::ExpectedSingleArgument => { + diag.span_note(self.span, "expected a single argument here"); + } + AttributeParseErrorReason::ExpectedSpecificArgument(possibilities) => { + match possibilities.as_slice() { + &[] => {} + &[x] => { + diag.span_note(self.span, format!("the only valid argument here is `{x}`")); + } + [first, second] => { + diag.span_note( + self.span, + format!("valid arguments are `{first}` or `{second}`"), + ); + } + [first @ .., second_to_last, last] => { + let mut res = String::new(); + for i in first { + res.push_str(&format!("`{i}`, ")); + } + res.push_str(&format!("`{second_to_last}` or `{last}`")); + + diag.span_note(self.span, format!("valid arguments are {res}")); + } + } + } + } + + let suggestions = self.template.suggestions(false, &name); + diag.span_suggestions( + self.attr_span, + if suggestions.len() == 1 { + "must be of the form" + } else { + "the following are possible correct uses" + }, + suggestions, + Applicability::HasPlaceholders, + ); + + diag + } +} diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 8388fd267f587..188a9a98ce7a0 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,9 +1,7 @@ use std::str::FromStr; use rustc_abi::ExternAbi; -use rustc_ast::expand::autodiff_attrs::{ - AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity, -}; +use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr}; use rustc_attr_data_structures::ReprAttr::ReprAlign; use rustc_attr_data_structures::{ @@ -86,7 +84,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let rust_target_features = tcx.rust_target_features(LOCAL_CRATE); - let mut inline_span = None; let mut link_ordinal_span = None; let mut no_sanitize_span = None; let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default(); @@ -452,8 +449,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx); - codegen_fn_attrs.inline = - find_attr!(attrs, AttributeKind::Inline(i, _) => *i).unwrap_or(InlineAttr::None); + let inline_span; + (codegen_fn_attrs.inline, inline_span) = if let Some((inline_attr, span)) = + find_attr!(attrs, AttributeKind::Inline(i, span) => (*i, *span)) + { + (inline_attr, Some(span)) + } else { + (InlineAttr::None, None) + }; // naked function MUST NOT be inlined! This attribute is required for the rust compiler itself, // but not for the code generation backend because at that point the naked function will just be @@ -474,7 +477,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { return OptimizeAttr::Default; }; - inline_span = Some(attr.span()); let [item] = &items[..] else { tcx.dcx().emit_err(errors::ExpectedOneArgumentOptimize { span: attr.span() }); return OptimizeAttr::Default; diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 73a21789c5d25..1df97fe6ffb95 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -111,6 +111,7 @@ pub enum AttributeGate { Ungated, } +// FIXME(jdonszelmann): move to rustc_attr_data_structures /// A template that the attribute input must match. /// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. #[derive(Clone, Copy, Default)] @@ -127,6 +128,26 @@ pub struct AttributeTemplate { pub name_value_str: Option<&'static str>, } +impl AttributeTemplate { + pub fn suggestions(&self, inner: bool, name: impl std::fmt::Display) -> Vec { + let mut suggestions = vec![]; + let inner = if inner { "!" } else { "" }; + if self.word { + suggestions.push(format!("#{inner}[{name}]")); + } + if let Some(descr) = self.list { + suggestions.push(format!("#{inner}[{name}({descr})]")); + } + suggestions.extend(self.one_of.iter().map(|&word| format!("#{inner}[{name}({word})]"))); + if let Some(descr) = self.name_value_str { + suggestions.push(format!("#{inner}[{name} = \"{descr}\"]")); + } + suggestions.sort(); + + suggestions + } +} + /// How to handle multiple duplicate attributes on the same item. #[derive(Clone, Copy, Default)] pub enum AttributeDuplicates { @@ -181,20 +202,21 @@ pub enum AttributeDuplicates { /// A convenience macro for constructing attribute templates. /// E.g., `template!(Word, List: "description")` means that the attribute /// supports forms `#[attr]` and `#[attr(description)]`. +#[macro_export] macro_rules! template { - (Word) => { template!(@ true, None, &[], None) }; - (List: $descr: expr) => { template!(@ false, Some($descr), &[], None) }; - (OneOf: $one_of: expr) => { template!(@ false, None, $one_of, None) }; - (NameValueStr: $descr: expr) => { template!(@ false, None, &[], Some($descr)) }; - (Word, List: $descr: expr) => { template!(@ true, Some($descr), &[], None) }; - (Word, NameValueStr: $descr: expr) => { template!(@ true, None, &[], Some($descr)) }; + (Word) => { $crate::template!(@ true, None, &[], None) }; + (List: $descr: expr) => { $crate::template!(@ false, Some($descr), &[], None) }; + (OneOf: $one_of: expr) => { $crate::template!(@ false, None, $one_of, None) }; + (NameValueStr: $descr: expr) => { $crate::template!(@ false, None, &[], Some($descr)) }; + (Word, List: $descr: expr) => { $crate::template!(@ true, Some($descr), &[], None) }; + (Word, NameValueStr: $descr: expr) => { $crate::template!(@ true, None, &[], Some($descr)) }; (List: $descr1: expr, NameValueStr: $descr2: expr) => { - template!(@ false, Some($descr1), &[], Some($descr2)) + $crate::template!(@ false, Some($descr1), &[], Some($descr2)) }; (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => { - template!(@ true, Some($descr1), &[], Some($descr2)) + $crate::template!(@ true, Some($descr1), &[], Some($descr2)) }; - (@ $word: expr, $list: expr, $one_of: expr, $name_value_str: expr) => { AttributeTemplate { + (@ $word: expr, $list: expr, $one_of: expr, $name_value_str: expr) => { $crate::AttributeTemplate { word: $word, list: $list, one_of: $one_of, name_value_str: $name_value_str } }; } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index f91ff9dc91613..9c4e1aea9f8b4 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2622,6 +2622,7 @@ pub(crate) struct UnusedCrateDependency { pub local_crate: Symbol, } +// FIXME(jdonszelmann): duplicated in rustc_attr_parsing, should be moved there completely. #[derive(LintDiagnostic)] #[diag(lint_ill_formed_attribute_input)] pub(crate) struct IllFormedAttributeInput { diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 555ab3cdb2b6e..1c12e8c189d15 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -282,11 +282,15 @@ fn emit_malformed_attribute( name: Symbol, template: AttributeTemplate, ) { + // attrs with new parsers are locally validated so excluded here + if matches!(name, sym::inline | sym::rustc_force_inline) { + return; + } + // Some of previously accepted forms were used in practice, // report them as warnings for now. - let should_warn = |name| { - matches!(name, sym::doc | sym::ignore | sym::inline | sym::link | sym::test | sym::bench) - }; + let should_warn = + |name| matches!(name, sym::doc | sym::ignore | sym::link | sym::test | sym::bench); let error_msg = format!("malformed `{name}` attribute input"); let mut suggestions = vec![]; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 737f1e31fca9b..59f17ac4dcf74 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -124,6 +124,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::Stability { span, .. } | AttributeKind::ConstStability { span, .. }, ) => self.check_stability_promotable(*span, target), + Attribute::Parsed(AttributeKind::Inline(InlineAttr::Force { .. }, ..)) => {} // handled separately below Attribute::Parsed(AttributeKind::Inline(kind, attr_span)) => { self.check_inline(hir_id, *attr_span, span, kind, target) } @@ -682,6 +683,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) => { continue; } + Attribute::Parsed(AttributeKind::Inline(.., span)) => { + self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { + span: *span, + naked_span: attr.span(), + attr: sym::inline.to_string(), + }); + + return; + } + // FIXME(jdonszelmann): make exhaustive _ => {} } @@ -2902,7 +2913,8 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) { let attrs = tcx.hir_attrs(item.hir_id()); - if let Some(attr_span) = find_attr!(attrs, AttributeKind::Inline(_, span) => *span) { + if let Some(attr_span) = find_attr!(attrs, AttributeKind::Inline(i, span) if !matches!(i, InlineAttr::Force{..}) => *span) + { tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span }); } } diff --git a/tests/ui/attributes/multiple-invalid.stderr b/tests/ui/attributes/multiple-invalid.stderr index a8dba0ba37d3a..f4f7dd7c4f1f8 100644 --- a/tests/ui/attributes/multiple-invalid.stderr +++ b/tests/ui/attributes/multiple-invalid.stderr @@ -1,12 +1,3 @@ -error[E0518]: attribute should be applied to function or closure - --> $DIR/multiple-invalid.rs:4:1 - | -LL | #[inline] - | ^^^^^^^^^ -... -LL | const FOO: u8 = 0; - | ------------------ not a function or closure - error: attribute should be applied to a function definition --> $DIR/multiple-invalid.rs:6:1 | @@ -16,6 +7,15 @@ LL | LL | const FOO: u8 = 0; | ------------------ not a function definition +error[E0518]: attribute should be applied to function or closure + --> $DIR/multiple-invalid.rs:4:1 + | +LL | #[inline] + | ^^^^^^^^^ +... +LL | const FOO: u8 = 0; + | ------------------ not a function or closure + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0518`. diff --git a/tests/ui/error-codes/E0534.rs b/tests/ui/error-codes/E0534.rs index a424249941979..db29e6801f582 100644 --- a/tests/ui/error-codes/E0534.rs +++ b/tests/ui/error-codes/E0534.rs @@ -1,4 +1,4 @@ -#[inline()] //~ ERROR E0534 +#[inline()] //~ ERROR malformed `inline` attribute input pub fn something() {} fn main() { diff --git a/tests/ui/error-codes/E0534.stderr b/tests/ui/error-codes/E0534.stderr index 6983de7ab69c6..f63d80c220cec 100644 --- a/tests/ui/error-codes/E0534.stderr +++ b/tests/ui/error-codes/E0534.stderr @@ -1,9 +1,22 @@ -error[E0534]: expected one argument +error[E0539]: malformed `inline` attribute input --> $DIR/E0534.rs:1:1 | LL | #[inline()] | ^^^^^^^^^^^ + | +note: expected a single argument here + --> $DIR/E0534.rs:1:9 + | +LL | #[inline()] + | ^^ +help: the following are possible correct uses + | +LL | #[inline(always|never)] + | ++++++++++++ +LL - #[inline()] +LL + #[inline] + | error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0534`. +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr index bdca6163473c6..a9ef0bbc6e78b 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr @@ -8,7 +8,7 @@ LL | #![rustc_main] = note: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable = note: the `#[rustc_main]` attribute is used internally to specify test entry point function -error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]` +error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]` --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5 | LL | #[inline = "2100"] fn f() { } diff --git a/tests/ui/force-inlining/invalid.rs b/tests/ui/force-inlining/invalid.rs index 7574078b245c2..e9f5712413e80 100644 --- a/tests/ui/force-inlining/invalid.rs +++ b/tests/ui/force-inlining/invalid.rs @@ -9,7 +9,6 @@ // Test that invalid force inlining attributes error as expected. #[rustc_force_inline("foo")] -//~^ ERROR malformed `rustc_force_inline` attribute input pub fn forced1() { } diff --git a/tests/ui/force-inlining/invalid.stderr b/tests/ui/force-inlining/invalid.stderr index 92b3c314bad18..26259a4d61fe0 100644 --- a/tests/ui/force-inlining/invalid.stderr +++ b/tests/ui/force-inlining/invalid.stderr @@ -1,71 +1,80 @@ -error: malformed `rustc_force_inline` attribute input - --> $DIR/invalid.rs:11:1 - | -LL | #[rustc_force_inline("foo")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[rustc_force_inline("foo")] -LL + #[rustc_force_inline = "reason"] - | -LL - #[rustc_force_inline("foo")] -LL + #[rustc_force_inline] +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/invalid.rs:132:11 | +LL | fn barqux(#[rustc_force_inline] _x: u32) {} + | ^^^^^^^^^^^^^^^^^^^^^ -error: malformed `rustc_force_inline` attribute input - --> $DIR/invalid.rs:16:1 +error[E0539]: malformed `rustc_force_inline` attribute input + --> $DIR/invalid.rs:15:1 | LL | #[rustc_force_inline(bar, baz)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: the following are the possible correct uses +note: expected a single argument here + --> $DIR/invalid.rs:15:21 + | +LL | #[rustc_force_inline(bar, baz)] + | ^^^^^^^^^^ +help: the following are possible correct uses | LL - #[rustc_force_inline(bar, baz)] LL + #[rustc_force_inline = "reason"] | LL - #[rustc_force_inline(bar, baz)] +LL + #[rustc_force_inline(reason)] + | +LL - #[rustc_force_inline(bar, baz)] LL + #[rustc_force_inline] | -error: malformed `rustc_force_inline` attribute input - --> $DIR/invalid.rs:21:1 +error[E0539]: malformed `rustc_force_inline` attribute input + --> $DIR/invalid.rs:20:1 | LL | #[rustc_force_inline(2)] | ^^^^^^^^^^^^^^^^^^^^^^^^ | -help: the following are the possible correct uses +note: expected a string literal here + --> $DIR/invalid.rs:20:22 + | +LL | #[rustc_force_inline(2)] + | ^ +help: the following are possible correct uses | LL - #[rustc_force_inline(2)] LL + #[rustc_force_inline = "reason"] | LL - #[rustc_force_inline(2)] +LL + #[rustc_force_inline(reason)] + | +LL - #[rustc_force_inline(2)] LL + #[rustc_force_inline] | -error: malformed `rustc_force_inline` attribute input - --> $DIR/invalid.rs:26:1 +error[E0539]: malformed `rustc_force_inline` attribute input + --> $DIR/invalid.rs:25:1 | LL | #[rustc_force_inline = 2] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: the following are the possible correct uses +note: expected a string literal here + --> $DIR/invalid.rs:25:24 + | +LL | #[rustc_force_inline = 2] + | ^ +help: the following are possible correct uses | LL - #[rustc_force_inline = 2] LL + #[rustc_force_inline = "reason"] | LL - #[rustc_force_inline = 2] -LL + #[rustc_force_inline] +LL + #[rustc_force_inline(reason)] | - -error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters - --> $DIR/invalid.rs:133:11 +LL - #[rustc_force_inline = 2] +LL + #[rustc_force_inline] | -LL | fn barqux(#[rustc_force_inline] _x: u32) {} - | ^^^^^^^^^^^^^^^^^^^^^ error: attribute should be applied to a function - --> $DIR/invalid.rs:31:1 + --> $DIR/invalid.rs:30:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -74,7 +83,7 @@ LL | extern crate std as other_std; | ------------------------------ not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:35:1 + --> $DIR/invalid.rs:34:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -83,7 +92,7 @@ LL | use std::collections::HashMap; | ------------------------------ not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:39:1 + --> $DIR/invalid.rs:38:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -92,7 +101,7 @@ LL | static _FOO: &'static str = "FOO"; | ---------------------------------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:43:1 + --> $DIR/invalid.rs:42:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -101,7 +110,7 @@ LL | const _BAR: u32 = 3; | -------------------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:47:1 + --> $DIR/invalid.rs:46:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -110,7 +119,7 @@ LL | mod foo { } | ----------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:51:1 + --> $DIR/invalid.rs:50:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -125,7 +134,7 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:67:1 + --> $DIR/invalid.rs:66:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -134,7 +143,7 @@ LL | type Foo = u32; | --------------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:71:1 + --> $DIR/invalid.rs:70:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -147,13 +156,13 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:73:10 + --> $DIR/invalid.rs:72:10 | LL | enum Bar<#[rustc_force_inline] T> { | ^^^^^^^^^^^^^^^^^^^^^ - not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:75:5 + --> $DIR/invalid.rs:74:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -162,7 +171,7 @@ LL | Baz(std::marker::PhantomData), | -------------------------------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:80:1 + --> $DIR/invalid.rs:79:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -175,7 +184,7 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:83:5 + --> $DIR/invalid.rs:82:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -184,7 +193,7 @@ LL | field: u32, | ---------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:88:1 + --> $DIR/invalid.rs:87:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -196,7 +205,7 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:95:1 + --> $DIR/invalid.rs:94:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -211,7 +220,7 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:110:1 + --> $DIR/invalid.rs:109:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -220,7 +229,7 @@ LL | trait FooQux = FooBaz; | ---------------------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:114:1 + --> $DIR/invalid.rs:113:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -233,7 +242,7 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:122:1 + --> $DIR/invalid.rs:121:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -245,7 +254,7 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:129:1 + --> $DIR/invalid.rs:128:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -254,7 +263,7 @@ LL | macro_rules! barqux { ($foo:tt) => { $foo }; } | ---------------------------------------------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:133:11 + --> $DIR/invalid.rs:132:11 | LL | fn barqux(#[rustc_force_inline] _x: u32) {} | ^^^^^^^^^^^^^^^^^^^^^-------- @@ -262,7 +271,7 @@ LL | fn barqux(#[rustc_force_inline] _x: u32) {} | not a function definition error: attribute cannot be applied to a `async`, `gen` or `async gen` function - --> $DIR/invalid.rs:137:1 + --> $DIR/invalid.rs:136:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -271,7 +280,7 @@ LL | async fn async_foo() {} | -------------------- `async`, `gen` or `async gen` function error: attribute cannot be applied to a `async`, `gen` or `async gen` function - --> $DIR/invalid.rs:141:1 + --> $DIR/invalid.rs:140:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -280,7 +289,7 @@ LL | gen fn gen_foo() {} | ---------------- `async`, `gen` or `async gen` function error: attribute cannot be applied to a `async`, `gen` or `async gen` function - --> $DIR/invalid.rs:145:1 + --> $DIR/invalid.rs:144:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -289,19 +298,19 @@ LL | async gen fn async_gen_foo() {} | ---------------------------- `async`, `gen` or `async gen` function error: attribute should be applied to a function - --> $DIR/invalid.rs:150:14 + --> $DIR/invalid.rs:149:14 | LL | let _x = #[rustc_force_inline] || { }; | ^^^^^^^^^^^^^^^^^^^^^ ------ not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:152:14 + --> $DIR/invalid.rs:151:14 | LL | let _y = #[rustc_force_inline] 3 + 4; | ^^^^^^^^^^^^^^^^^^^^^ - not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:154:5 + --> $DIR/invalid.rs:153:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -310,7 +319,7 @@ LL | let _z = 3; | ----------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:159:9 + --> $DIR/invalid.rs:158:9 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -319,7 +328,7 @@ LL | 1 => (), | ------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:98:5 + --> $DIR/invalid.rs:97:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -328,7 +337,7 @@ LL | type Foo; | --------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:101:5 + --> $DIR/invalid.rs:100:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -337,7 +346,7 @@ LL | const Bar: i32; | --------------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:105:5 + --> $DIR/invalid.rs:104:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -346,7 +355,7 @@ LL | fn foo() {} | ----------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:117:5 + --> $DIR/invalid.rs:116:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -355,7 +364,7 @@ LL | fn foo() {} | ----------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:54:5 + --> $DIR/invalid.rs:53:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -364,7 +373,7 @@ LL | static X: &'static u32; | ----------------------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:58:5 + --> $DIR/invalid.rs:57:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -373,7 +382,7 @@ LL | type Y; | ------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:62:5 + --> $DIR/invalid.rs:61:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -381,5 +390,6 @@ LL | LL | fn foo(); | --------- not a function definition -error: aborting due to 38 previous errors +error: aborting due to 37 previous errors +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/invalid/invalid-inline.rs b/tests/ui/invalid/invalid-inline.rs index 2501b1e23f2f1..6735e1d814d89 100644 --- a/tests/ui/invalid/invalid-inline.rs +++ b/tests/ui/invalid/invalid-inline.rs @@ -1,10 +1,10 @@ #![allow(dead_code)] -#[inline(please,no)] //~ ERROR expected one argument +#[inline(please,no)] //~ ERROR malformed `inline` attribute fn a() { } -#[inline()] //~ ERROR expected one argument +#[inline()] //~ ERROR malformed `inline` attribute fn b() { } diff --git a/tests/ui/invalid/invalid-inline.stderr b/tests/ui/invalid/invalid-inline.stderr index 7edbf936b1b4d..965da7e756705 100644 --- a/tests/ui/invalid/invalid-inline.stderr +++ b/tests/ui/invalid/invalid-inline.stderr @@ -1,15 +1,42 @@ -error[E0534]: expected one argument +error[E0539]: malformed `inline` attribute input --> $DIR/invalid-inline.rs:3:1 | LL | #[inline(please,no)] | ^^^^^^^^^^^^^^^^^^^^ + | +note: expected a single argument here + --> $DIR/invalid-inline.rs:3:9 + | +LL | #[inline(please,no)] + | ^^^^^^^^^^^ +help: the following are possible correct uses + | +LL - #[inline(please,no)] +LL + #[inline(always|never)] + | +LL - #[inline(please,no)] +LL + #[inline] + | -error[E0534]: expected one argument +error[E0539]: malformed `inline` attribute input --> $DIR/invalid-inline.rs:7:1 | LL | #[inline()] | ^^^^^^^^^^^ + | +note: expected a single argument here + --> $DIR/invalid-inline.rs:7:9 + | +LL | #[inline()] + | ^^ +help: the following are possible correct uses + | +LL | #[inline(always|never)] + | ++++++++++++ +LL - #[inline()] +LL + #[inline] + | error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0534`. +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/issues/issue-43988.rs b/tests/ui/issues/issue-43988.rs index b114e8e03333d..5fea5576b7f03 100644 --- a/tests/ui/issues/issue-43988.rs +++ b/tests/ui/issues/issue-43988.rs @@ -9,7 +9,7 @@ fn main() { #[inline(XYZ)] let _b = 4; - //~^^ ERROR attribute should be applied to function or closure + //~^^ ERROR malformed `inline` attribute #[repr(nothing)] let _x = 0; @@ -29,7 +29,7 @@ fn main() { #[inline(ABC)] foo(); - //~^^ ERROR attribute should be applied to function or closure + //~^^ ERROR malformed `inline` attribute let _z = #[repr] 1; //~^ ERROR malformed `repr` attribute diff --git a/tests/ui/issues/issue-43988.stderr b/tests/ui/issues/issue-43988.stderr index d629f199b223d..74c3e81cb1c47 100644 --- a/tests/ui/issues/issue-43988.stderr +++ b/tests/ui/issues/issue-43988.stderr @@ -10,6 +10,26 @@ error: malformed `repr` attribute input LL | let _z = #[repr] 1; | ^^^^^^^ help: must be of the form: `#[repr(C)]` +error[E0539]: malformed `inline` attribute input + --> $DIR/issue-43988.rs:10:5 + | +LL | #[inline(XYZ)] + | ^^^^^^^^^^^^^^ + | +note: valid arguments are `always` or `never` + --> $DIR/issue-43988.rs:10:14 + | +LL | #[inline(XYZ)] + | ^^^ +help: the following are possible correct uses + | +LL - #[inline(XYZ)] +LL + #[inline(always|never)] + | +LL - #[inline(XYZ)] +LL + #[inline] + | + error[E0552]: unrecognized representation hint --> $DIR/issue-43988.rs:14:12 | @@ -26,6 +46,26 @@ LL | #[repr(something_not_real)] | = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` +error[E0539]: malformed `inline` attribute input + --> $DIR/issue-43988.rs:30:5 + | +LL | #[inline(ABC)] + | ^^^^^^^^^^^^^^ + | +note: valid arguments are `always` or `never` + --> $DIR/issue-43988.rs:30:14 + | +LL | #[inline(ABC)] + | ^^^ +help: the following are possible correct uses + | +LL - #[inline(ABC)] +LL + #[inline(always|never)] + | +LL - #[inline(ABC)] +LL + #[inline] + | + error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43988.rs:5:5 | @@ -34,23 +74,7 @@ LL | #[inline] LL | let _a = 4; | ----------- not a function or closure -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43988.rs:10:5 - | -LL | #[inline(XYZ)] - | ^^^^^^^^^^^^^^ -LL | let _b = 4; - | ----------- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43988.rs:30:5 - | -LL | #[inline(ABC)] - | ^^^^^^^^^^^^^^ -LL | foo(); - | ----- not a function or closure - error: aborting due to 7 previous errors -Some errors have detailed explanations: E0518, E0552. +Some errors have detailed explanations: E0518, E0539, E0552. For more information about an error, try `rustc --explain E0518`. diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 769b174874b96..5ea623a713e85 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -1,3 +1,21 @@ +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:74:1 + | +LL | #[inline(never)] + | ^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:73:1 + | +LL | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +note: the lint level is defined here + --> $DIR/unused-attr-duplicate.rs:12:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + error: unused attribute --> $DIR/unused-attr-duplicate.rs:33:1 | @@ -9,11 +27,6 @@ note: attribute also specified here | LL | #[no_link] | ^^^^^^^^^^ -note: the lint level is defined here - --> $DIR/unused-attr-duplicate.rs:12:9 - | -LL | #![deny(unused_attributes)] - | ^^^^^^^^^^^^^^^^^ error: unused attribute --> $DIR/unused-attr-duplicate.rs:37:1 @@ -102,19 +115,6 @@ note: attribute also specified here LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:74:1 - | -LL | #[inline(never)] - | ^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:73:1 - | -LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - error: unused attribute --> $DIR/unused-attr-duplicate.rs:77:1 | diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout index 6b41eb530dbc8..834954d8dc0cd 100644 --- a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout +++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout @@ -8,7 +8,7 @@ extern crate std; // issue#97006 macro_rules! m { ($attr_path: path) => { #[$attr_path] fn f() {} } } -#[inline] +#[attr="Inline(Hint)")] fn f() { } fn main() { } diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr index e1dbdb9ab3c66..535db55a13d61 100644 --- a/tests/ui/malformed/malformed-regressions.stderr +++ b/tests/ui/malformed/malformed-regressions.stderr @@ -17,15 +17,6 @@ LL | #[ignore()] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 -error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]` - --> $DIR/malformed-regressions.rs:5:1 - | -LL | #[inline = ""] - | ^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]` --> $DIR/malformed-regressions.rs:7:1 | @@ -44,5 +35,14 @@ LL | #[link = ""] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 +error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]` + --> $DIR/malformed-regressions.rs:5:1 + | +LL | #[inline = ""] + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + error: aborting due to 5 previous errors diff --git a/tests/ui/span/E0535.rs b/tests/ui/span/E0535.rs index e26334e9bbdc6..e0c6dbfc591f6 100644 --- a/tests/ui/span/E0535.rs +++ b/tests/ui/span/E0535.rs @@ -1,4 +1,4 @@ -#[inline(unknown)] //~ ERROR E0535 +#[inline(unknown)] //~ ERROR malformed `inline` attribute pub fn something() {} fn main() { diff --git a/tests/ui/span/E0535.stderr b/tests/ui/span/E0535.stderr index 9060b687f508c..54dcdd8957902 100644 --- a/tests/ui/span/E0535.stderr +++ b/tests/ui/span/E0535.stderr @@ -1,11 +1,23 @@ -error[E0535]: invalid argument +error[E0539]: malformed `inline` attribute input + --> $DIR/E0535.rs:1:1 + | +LL | #[inline(unknown)] + | ^^^^^^^^^^^^^^^^^^ + | +note: valid arguments are `always` or `never` --> $DIR/E0535.rs:1:10 | LL | #[inline(unknown)] | ^^^^^^^ +help: the following are possible correct uses + | +LL - #[inline(unknown)] +LL + #[inline(always|never)] + | +LL - #[inline(unknown)] +LL + #[inline] | - = help: valid inline arguments are `always` and `never` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0535`. +For more information about this error, try `rustc --explain E0539`. From 2eafc9fb4cbe731997cf3561a0201fce130cf9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 5 Mar 2025 14:35:54 +0100 Subject: [PATCH 5/7] use consistent attr errors in all attribute parsers --- compiler/rustc_attr_parsing/messages.ftl | 5 - .../src/attributes/confusables.rs | 12 +-- .../src/attributes/deprecation.rs | 15 ++- .../src/attributes/inline.rs | 2 +- .../src/attributes/stability.rs | 39 ++++---- .../src/attributes/transparency.rs | 13 ++- compiler/rustc_attr_parsing/src/context.rs | 73 ++++++++++++-- .../src/session_diagnostics.rs | 74 +++++++------- compiler/rustc_codegen_ssa/src/errors.rs | 15 --- compiler/rustc_parse/src/validate_attr.rs | 2 +- tests/ui/attributes/rustc_confusables.rs | 4 +- tests/ui/attributes/rustc_confusables.stderr | 31 +++--- tests/ui/deprecation/deprecation-sanity.rs | 10 +- .../ui/deprecation/deprecation-sanity.stderr | 97 +++++++++++++++++-- tests/ui/error-codes/E0534.stderr | 2 +- tests/ui/force-inlining/invalid.stderr | 6 +- tests/ui/invalid/invalid-inline.stderr | 4 +- tests/ui/issues/issue-43988.stderr | 4 +- tests/ui/span/E0535.stderr | 2 +- .../stability-attribute-sanity-2.rs | 2 +- .../stability-attribute-sanity-2.stderr | 10 +- .../stability-attribute-sanity.rs | 8 +- .../stability-attribute-sanity.stderr | 32 +++++- 23 files changed, 308 insertions(+), 154 deletions(-) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 2687bfdc7168e..70de83f2f7443 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -27,8 +27,6 @@ attr_parsing_ill_formed_attribute_input = {$num_suggestions -> [1] attribute must be of the form {$suggestions} *[other] valid forms for the attribute are {$suggestions} } -attr_parsing_incorrect_meta_item = expected a quoted string literal -attr_parsing_incorrect_meta_item_suggestion = consider surrounding this with quotes attr_parsing_incorrect_repr_format_align_one_arg = incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses @@ -85,9 +83,6 @@ attr_parsing_missing_note = attr_parsing_missing_since = missing 'since' -attr_parsing_multiple_item = - multiple '{$item}' items - attr_parsing_multiple_stability_levels = multiple stability levels diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index 0be9d690c32d3..f4505cbc0e1b7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -19,9 +19,7 @@ impl AttributeParser for ConfusablesParser { template!(List: r#""name1", "name2", ..."#), |this, cx, args| { let Some(list) = args.list() else { - // FIXME(jdonszelmann): error when not a list? Bring validation code here. - // NOTE: currently subsequent attributes are silently ignored using - // tcx.get_attr(). + cx.expected_list(cx.attr_span); return; }; @@ -33,13 +31,7 @@ impl AttributeParser for ConfusablesParser { let span = param.span(); let Some(lit) = param.lit() else { - cx.emit_err(session_diagnostics::IncorrectMetaItem { - span, - suggestion: Some(session_diagnostics::IncorrectMetaItemSuggestion { - lo: span.shrink_to_lo(), - hi: span.shrink_to_hi(), - }), - }); + cx.expected_string_literal(span); continue; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 692f587ba037e..0983a153efa98 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -19,7 +19,7 @@ fn get( item: &Option, ) -> Option { if item.is_some() { - cx.emit_err(session_diagnostics::MultipleItem { span: param_span, item: name.to_string() }); + cx.duplicate_key(param_span, name); return None; } if let Some(v) = arg.name_value() { @@ -36,8 +36,7 @@ fn get( None } } else { - // FIXME(jdonszelmann): suggestion? - cx.emit_err(session_diagnostics::IncorrectMetaItem { span: param_span, suggestion: None }); + cx.expected_name_value(param_span, Some(name)); None } } @@ -99,15 +98,15 @@ impl SingleAttributeParser for DeprecationParser { suggestion = Some(get(cx, name, param_span, param.args(), &suggestion)?); } _ => { - cx.emit_err(session_diagnostics::UnknownMetaItem { - span: param_span, - item: param.path().to_string(), - expected: if features.deprecated_suggestion() { + cx.unknown_key( + param_span, + param.path().to_string(), + if features.deprecated_suggestion() { &["since", "note", "suggestion"] } else { &["since", "note"] }, - }); + ); return None; } } diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index da56656e3ed34..75ae1d6a6c173 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -29,7 +29,7 @@ impl SingleAttributeParser for InlineParser { return None; }; - match l.meta_item().and_then(|i| i.path().word().map(|i| i.name)) { + match l.meta_item().and_then(|i| i.path().word_sym()) { Some(sym::always) => { Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span)) } diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 993ce134dca5f..0eec9d2b7380c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -6,7 +6,7 @@ use rustc_attr_data_structures::{ }; use rustc_errors::ErrorGuaranteed; use rustc_feature::{AttributeTemplate, template}; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Ident, Span, Symbol, sym}; use super::util::parse_version; use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser}; @@ -217,12 +217,10 @@ fn insert_value_into_option_or_error( cx: &AcceptContext<'_, '_, S>, param: &MetaItemParser<'_>, item: &mut Option, + name: Ident, ) -> Option<()> { if item.is_some() { - cx.emit_err(session_diagnostics::MultipleItem { - span: param.span(), - item: param.path().to_string(), - }); + cx.duplicate_key(name.span, name.name); None } else if let Some(v) = param.args().name_value() && let Some(s) = v.value_as_str() @@ -230,10 +228,7 @@ fn insert_value_into_option_or_error( *item = Some(s); Some(()) } else { - cx.emit_err(session_diagnostics::IncorrectMetaItem { - span: param.span(), - suggestion: None, - }); + cx.expected_name_value(param.span(), Some(name.name)); None } } @@ -259,9 +254,14 @@ pub(crate) fn parse_stability( return None; }; - match param.path().word_sym() { - Some(sym::feature) => insert_value_into_option_or_error(cx, ¶m, &mut feature)?, - Some(sym::since) => insert_value_into_option_or_error(cx, ¶m, &mut since)?, + let word = param.path().word(); + match word.map(|i| i.name) { + Some(sym::feature) => { + insert_value_into_option_or_error(cx, ¶m, &mut feature, word.unwrap())? + } + Some(sym::since) => { + insert_value_into_option_or_error(cx, ¶m, &mut since, word.unwrap())? + } _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param_span, @@ -327,11 +327,16 @@ pub(crate) fn parse_unstability( return None; }; - match param.path().word_sym() { - Some(sym::feature) => insert_value_into_option_or_error(cx, ¶m, &mut feature)?, - Some(sym::reason) => insert_value_into_option_or_error(cx, ¶m, &mut reason)?, + let word = param.path().word(); + match word.map(|i| i.name) { + Some(sym::feature) => { + insert_value_into_option_or_error(cx, ¶m, &mut feature, word.unwrap())? + } + Some(sym::reason) => { + insert_value_into_option_or_error(cx, ¶m, &mut reason, word.unwrap())? + } Some(sym::issue) => { - insert_value_into_option_or_error(cx, ¶m, &mut issue)?; + insert_value_into_option_or_error(cx, ¶m, &mut issue, word.unwrap())?; // These unwraps are safe because `insert_value_into_option_or_error` ensures the meta item // is a name/value pair string literal. @@ -361,7 +366,7 @@ pub(crate) fn parse_unstability( is_soft = true; } Some(sym::implied_by) => { - insert_value_into_option_or_error(cx, ¶m, &mut implied_by)? + insert_value_into_option_or_error(cx, ¶m, &mut implied_by, word.unwrap())? } _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index b0f5dac7fe249..ce5ceb9139a5c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -22,12 +22,19 @@ impl SingleAttributeParser for TransparencyParser { template!(NameValueStr: "transparent|semitransparent|opaque"); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { - match args.name_value().and_then(|nv| nv.value_as_str()) { + let Some(nv) = args.name_value() else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + match nv.value_as_str() { Some(sym::transparent) => Some(Transparency::Transparent), Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque), Some(sym::opaque) => Some(Transparency::Opaque), - Some(other) => { - cx.dcx().span_err(cx.attr_span, format!("unknown macro transparency: `{other}`")); + Some(_) => { + cx.expected_specific_argument_strings( + nv.value_span, + vec!["transparent", "semitransparent", "opaque"], + ); None } None => None, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index ff0b8daec50ca..87f2f609ef821 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -26,7 +26,7 @@ use crate::attributes::stability::{ use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single}; use crate::parser::{ArgParser, MetaItemParser}; -use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason}; +use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem}; macro_rules! group_type { ($stage: ty) => { @@ -189,8 +189,16 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { (self.emit_lint)(AttributeLint { id, span, kind: lint }); } + pub(crate) fn unknown_key( + &self, + span: Span, + found: String, + options: &'static [&'static str], + ) -> ErrorGuaranteed { + self.emit_err(UnknownMetaItem { span, item: found, expected: options }) + } + pub(crate) fn expected_string_literal(&self, span: Span) -> ErrorGuaranteed { - // 539? self.emit_err(AttributeParseError { span, attr_span: self.attr_span, @@ -200,12 +208,40 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } - // pub(crate) fn expected_any_arguments(&self, span: Span) -> ErrorGuaranteed { - // - // } + pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedList, + }) + } + + /// emit an error that a `name = value` pair was expected at this span. The symbol can be given for + /// a nicer error message talking about the specific name that was found lacking a value. + pub(crate) fn expected_name_value(&self, span: Span, name: Option) -> ErrorGuaranteed { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedNameValue(name), + }) + } + + /// emit an error that a `name = value` pair was found where that name was already seen. + pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::DuplicateKey(key), + }) + } pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed { - // E534? self.emit_err(AttributeParseError { span, attr_span: self.attr_span, @@ -218,15 +254,34 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { pub(crate) fn expected_specific_argument( &self, span: Span, - options: Vec<&'static str>, + possibilities: Vec<&'static str>, + ) -> ErrorGuaranteed { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedSpecificArgument { + possibilities, + strings: false, + }, + }) + } + + pub(crate) fn expected_specific_argument_strings( + &self, + span: Span, + possibilities: Vec<&'static str>, ) -> ErrorGuaranteed { - // E535? self.emit_err(AttributeParseError { span, attr_span: self.attr_span, template: self.template.clone(), attribute: self.attr_path.clone(), - reason: AttributeParseErrorReason::ExpectedSpecificArgument(options), + reason: AttributeParseErrorReason::ExpectedSpecificArgument { + possibilities, + strings: true, + }, }) } } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 08cd8b5df2d69..3d865c1d14e7f 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -36,37 +36,6 @@ pub(crate) struct InvalidPredicate { pub predicate: String, } -#[derive(Diagnostic)] -#[diag(attr_parsing_multiple_item, code = E0538)] -pub(crate) struct MultipleItem { - #[primary_span] - pub span: Span, - - pub item: String, -} - -#[derive(Diagnostic)] -#[diag(attr_parsing_incorrect_meta_item, code = E0539)] -pub(crate) struct IncorrectMetaItem { - #[primary_span] - pub span: Span, - - #[subdiagnostic] - pub suggestion: Option, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion( - attr_parsing_incorrect_meta_item_suggestion, - applicability = "maybe-incorrect" -)] -pub(crate) struct IncorrectMetaItemSuggestion { - #[suggestion_part(code = "\"")] - pub lo: Span, - #[suggestion_part(code = "\"")] - pub hi: Span, -} - /// Error code: E0541 pub(crate) struct UnknownMetaItem<'a> { pub span: Span, @@ -506,7 +475,10 @@ pub(crate) struct UnrecognizedReprHint { pub(crate) enum AttributeParseErrorReason { ExpectedStringLiteral, ExpectedSingleArgument, - ExpectedSpecificArgument(Vec<&'static str>), + ExpectedList, + ExpectedNameValue(Option), + DuplicateKey(Symbol), + ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool }, } pub(crate) struct AttributeParseError { @@ -531,24 +503,46 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { AttributeParseErrorReason::ExpectedSingleArgument => { diag.span_note(self.span, "expected a single argument here"); } - AttributeParseErrorReason::ExpectedSpecificArgument(possibilities) => { + AttributeParseErrorReason::ExpectedList => { + diag.span_note(self.span, "expected this to be a list"); + } + AttributeParseErrorReason::DuplicateKey(key) => { + diag.span_note(self.span, format!("found `{key}` used as a key more than once")); + diag.code(E0538); + } + AttributeParseErrorReason::ExpectedNameValue(None) => { + diag.span_note( + self.span, + format!("expected this to be of the form `{name} = \"...\"`"), + ); + } + AttributeParseErrorReason::ExpectedNameValue(Some(name)) => { + diag.span_note( + self.span, + format!("expected this to be of the form `{name} = \"...\"`"), + ); + } + AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings } => { + let quote = if strings { '"' } else { '`' }; match possibilities.as_slice() { &[] => {} &[x] => { - diag.span_note(self.span, format!("the only valid argument here is `{x}`")); - } - [first, second] => { diag.span_note( self.span, - format!("valid arguments are `{first}` or `{second}`"), + format!("the only valid argument here is {quote}{x}{quote}"), ); } + [first, second] => { + diag.span_note(self.span, format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}")); + } [first @ .., second_to_last, last] => { let mut res = String::new(); for i in first { - res.push_str(&format!("`{i}`, ")); + res.push_str(&format!("{quote}{i}{quote}, ")); } - res.push_str(&format!("`{second_to_last}` or `{last}`")); + res.push_str(&format!( + "{quote}{second_to_last}{quote} or {quote}{last}{quote}" + )); diag.span_note(self.span, format!("valid arguments are {res}")); } @@ -562,7 +556,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { if suggestions.len() == 1 { "must be of the form" } else { - "the following are possible correct uses" + "try changing it to one of the following valid forms of the attribute" }, suggestions, Applicability::HasPlaceholders, diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index f843347db9251..54702fcb5dea0 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -208,13 +208,6 @@ pub(crate) struct OutOfRangeInteger { pub span: Span, } -#[derive(Diagnostic)] -#[diag(codegen_ssa_expected_one_argument, code = E0534)] -pub(crate) struct ExpectedOneArgument { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(codegen_ssa_expected_one_argument, code = E0722)] pub(crate) struct ExpectedOneArgumentOptimize { @@ -222,14 +215,6 @@ pub(crate) struct ExpectedOneArgumentOptimize { pub span: Span, } -#[derive(Diagnostic)] -#[diag(codegen_ssa_invalid_argument, code = E0535)] -#[help] -pub(crate) struct InvalidArgument { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(codegen_ssa_invalid_argument, code = E0722)] pub(crate) struct InvalidArgumentOptimize { diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 1c12e8c189d15..2296ec1043256 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -283,7 +283,7 @@ fn emit_malformed_attribute( template: AttributeTemplate, ) { // attrs with new parsers are locally validated so excluded here - if matches!(name, sym::inline | sym::rustc_force_inline) { + if matches!(name, sym::inline | sym::rustc_force_inline | sym::rustc_confusables) { return; } diff --git a/tests/ui/attributes/rustc_confusables.rs b/tests/ui/attributes/rustc_confusables.rs index 93d9a7d572c77..a8095936cff7a 100644 --- a/tests/ui/attributes/rustc_confusables.rs +++ b/tests/ui/attributes/rustc_confusables.rs @@ -37,8 +37,8 @@ impl Bar { fn qux() {} #[rustc_confusables(invalid_meta_item)] - //~^ ERROR expected a quoted string literal - //~| HELP consider surrounding this with quotes + //~^ ERROR malformed `rustc_confusables` attribute input [E0539] + //~| HELP must be of the form fn quux() {} } diff --git a/tests/ui/attributes/rustc_confusables.stderr b/tests/ui/attributes/rustc_confusables.stderr index aba384ff8ac83..be16da2f873c7 100644 --- a/tests/ui/attributes/rustc_confusables.stderr +++ b/tests/ui/attributes/rustc_confusables.stderr @@ -1,25 +1,32 @@ -error: malformed `rustc_confusables` attribute input - --> $DIR/rustc_confusables.rs:34:5 - | -LL | #[rustc_confusables] - | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` - error: expected at least one confusable name --> $DIR/rustc_confusables.rs:30:5 | LL | #[rustc_confusables()] | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0539]: expected a quoted string literal - --> $DIR/rustc_confusables.rs:39:25 +error[E0539]: malformed `rustc_confusables` attribute input + --> $DIR/rustc_confusables.rs:34:5 + | +LL | #[rustc_confusables] + | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` + | +note: expected this to be a list + --> $DIR/rustc_confusables.rs:34:5 + | +LL | #[rustc_confusables] + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0539]: malformed `rustc_confusables` attribute input + --> $DIR/rustc_confusables.rs:39:5 | LL | #[rustc_confusables(invalid_meta_item)] - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` | -help: consider surrounding this with quotes +note: expected a string literal here + --> $DIR/rustc_confusables.rs:39:25 | -LL | #[rustc_confusables("invalid_meta_item")] - | + + +LL | #[rustc_confusables(invalid_meta_item)] + | ^^^^^^^^^^^^^^^^^ error: attribute should be applied to an inherent method --> $DIR/rustc_confusables.rs:45:1 diff --git a/tests/ui/deprecation/deprecation-sanity.rs b/tests/ui/deprecation/deprecation-sanity.rs index d5b149b18ed6a..e40b017378a6c 100644 --- a/tests/ui/deprecation/deprecation-sanity.rs +++ b/tests/ui/deprecation/deprecation-sanity.rs @@ -4,16 +4,16 @@ mod bogus_attribute_types_1 { #[deprecated(since = "a", note = "a", reason)] //~ ERROR unknown meta item 'reason' fn f1() { } - #[deprecated(since = "a", note)] //~ ERROR expected a quoted string literal + #[deprecated(since = "a", note)] //~ ERROR malformed `deprecated` attribute input [E0539] fn f2() { } - #[deprecated(since, note = "a")] //~ ERROR expected a quoted string literal + #[deprecated(since, note = "a")] //~ ERROR malformed `deprecated` attribute input [E0539] fn f3() { } - #[deprecated(since = "a", note(b))] //~ ERROR expected a quoted string literal + #[deprecated(since = "a", note(b))] //~ ERROR malformed `deprecated` attribute input [E0539] fn f5() { } - #[deprecated(since(b), note = "a")] //~ ERROR expected a quoted string literal + #[deprecated(since(b), note = "a")] //~ ERROR malformed `deprecated` attribute input [E0539] fn f6() { } #[deprecated(note = b"test")] //~ ERROR literal in `deprecated` value must be a string @@ -27,7 +27,7 @@ mod bogus_attribute_types_1 { #[deprecated(since = "a", note = "b")] //~ ERROR multiple `deprecated` attributes fn multiple1() { } -#[deprecated(since = "a", since = "b", note = "c")] //~ ERROR multiple 'since' items +#[deprecated(since = "a", since = "b", note = "c")] //~ ERROR malformed `deprecated` attribute input [E0538] fn f1() { } struct X; diff --git a/tests/ui/deprecation/deprecation-sanity.stderr b/tests/ui/deprecation/deprecation-sanity.stderr index 53047d40cb2ff..8854ebb70d200 100644 --- a/tests/ui/deprecation/deprecation-sanity.stderr +++ b/tests/ui/deprecation/deprecation-sanity.stderr @@ -4,29 +4,97 @@ error[E0541]: unknown meta item 'reason' LL | #[deprecated(since = "a", note = "a", reason)] | ^^^^^^ expected one of `since`, `note` -error[E0539]: expected a quoted string literal +error[E0539]: malformed `deprecated` attribute input + --> $DIR/deprecation-sanity.rs:7:5 + | +LL | #[deprecated(since = "a", note)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: expected this to be of the form `note = "..."` --> $DIR/deprecation-sanity.rs:7:31 | LL | #[deprecated(since = "a", note)] | ^^^^ +help: try changing it to one of the following valid forms of the attribute + | +LL - #[deprecated(since = "a", note)] +LL + #[deprecated = "reason"] + | +LL - #[deprecated(since = "a", note)] +LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] + | +LL - #[deprecated(since = "a", note)] +LL + #[deprecated] + | -error[E0539]: expected a quoted string literal +error[E0539]: malformed `deprecated` attribute input + --> $DIR/deprecation-sanity.rs:10:5 + | +LL | #[deprecated(since, note = "a")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: expected this to be of the form `since = "..."` --> $DIR/deprecation-sanity.rs:10:18 | LL | #[deprecated(since, note = "a")] | ^^^^^ +help: try changing it to one of the following valid forms of the attribute + | +LL - #[deprecated(since, note = "a")] +LL + #[deprecated = "reason"] + | +LL - #[deprecated(since, note = "a")] +LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] + | +LL - #[deprecated(since, note = "a")] +LL + #[deprecated] + | -error[E0539]: expected a quoted string literal +error[E0539]: malformed `deprecated` attribute input + --> $DIR/deprecation-sanity.rs:13:5 + | +LL | #[deprecated(since = "a", note(b))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: expected this to be of the form `note = "..."` --> $DIR/deprecation-sanity.rs:13:31 | LL | #[deprecated(since = "a", note(b))] | ^^^^^^^ +help: try changing it to one of the following valid forms of the attribute + | +LL - #[deprecated(since = "a", note(b))] +LL + #[deprecated = "reason"] + | +LL - #[deprecated(since = "a", note(b))] +LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] + | +LL - #[deprecated(since = "a", note(b))] +LL + #[deprecated] + | -error[E0539]: expected a quoted string literal +error[E0539]: malformed `deprecated` attribute input + --> $DIR/deprecation-sanity.rs:16:5 + | +LL | #[deprecated(since(b), note = "a")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: expected this to be of the form `since = "..."` --> $DIR/deprecation-sanity.rs:16:18 | LL | #[deprecated(since(b), note = "a")] | ^^^^^^^^ +help: try changing it to one of the following valid forms of the attribute + | +LL - #[deprecated(since(b), note = "a")] +LL + #[deprecated = "reason"] + | +LL - #[deprecated(since(b), note = "a")] +LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] + | +LL - #[deprecated(since(b), note = "a")] +LL + #[deprecated] + | error[E0565]: literal in `deprecated` value must be a string --> $DIR/deprecation-sanity.rs:19:25 @@ -54,11 +122,28 @@ note: attribute also specified here LL | #[deprecated(since = "a", note = "b")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0538]: multiple 'since' items +error[E0538]: malformed `deprecated` attribute input + --> $DIR/deprecation-sanity.rs:30:1 + | +LL | #[deprecated(since = "a", since = "b", note = "c")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: found `since` used as a key more than once --> $DIR/deprecation-sanity.rs:30:27 | LL | #[deprecated(since = "a", since = "b", note = "c")] - | ^^^^^^^^^^^ + | ^^^^^ +help: try changing it to one of the following valid forms of the attribute + | +LL - #[deprecated(since = "a", since = "b", note = "c")] +LL + #[deprecated = "reason"] + | +LL - #[deprecated(since = "a", since = "b", note = "c")] +LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] + | +LL - #[deprecated(since = "a", since = "b", note = "c")] +LL + #[deprecated] + | error: this `#[deprecated]` annotation has no effect --> $DIR/deprecation-sanity.rs:35:1 diff --git a/tests/ui/error-codes/E0534.stderr b/tests/ui/error-codes/E0534.stderr index f63d80c220cec..de97ef18b7356 100644 --- a/tests/ui/error-codes/E0534.stderr +++ b/tests/ui/error-codes/E0534.stderr @@ -9,7 +9,7 @@ note: expected a single argument here | LL | #[inline()] | ^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[inline(always|never)] | ++++++++++++ diff --git a/tests/ui/force-inlining/invalid.stderr b/tests/ui/force-inlining/invalid.stderr index 26259a4d61fe0..a12f633b3f26d 100644 --- a/tests/ui/force-inlining/invalid.stderr +++ b/tests/ui/force-inlining/invalid.stderr @@ -15,7 +15,7 @@ note: expected a single argument here | LL | #[rustc_force_inline(bar, baz)] | ^^^^^^^^^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[rustc_force_inline(bar, baz)] LL + #[rustc_force_inline = "reason"] @@ -38,7 +38,7 @@ note: expected a string literal here | LL | #[rustc_force_inline(2)] | ^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[rustc_force_inline(2)] LL + #[rustc_force_inline = "reason"] @@ -61,7 +61,7 @@ note: expected a string literal here | LL | #[rustc_force_inline = 2] | ^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[rustc_force_inline = 2] LL + #[rustc_force_inline = "reason"] diff --git a/tests/ui/invalid/invalid-inline.stderr b/tests/ui/invalid/invalid-inline.stderr index 965da7e756705..8a230351d324f 100644 --- a/tests/ui/invalid/invalid-inline.stderr +++ b/tests/ui/invalid/invalid-inline.stderr @@ -9,7 +9,7 @@ note: expected a single argument here | LL | #[inline(please,no)] | ^^^^^^^^^^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[inline(please,no)] LL + #[inline(always|never)] @@ -29,7 +29,7 @@ note: expected a single argument here | LL | #[inline()] | ^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[inline(always|never)] | ++++++++++++ diff --git a/tests/ui/issues/issue-43988.stderr b/tests/ui/issues/issue-43988.stderr index 74c3e81cb1c47..8e731db6f2e39 100644 --- a/tests/ui/issues/issue-43988.stderr +++ b/tests/ui/issues/issue-43988.stderr @@ -21,7 +21,7 @@ note: valid arguments are `always` or `never` | LL | #[inline(XYZ)] | ^^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[inline(XYZ)] LL + #[inline(always|never)] @@ -57,7 +57,7 @@ note: valid arguments are `always` or `never` | LL | #[inline(ABC)] | ^^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[inline(ABC)] LL + #[inline(always|never)] diff --git a/tests/ui/span/E0535.stderr b/tests/ui/span/E0535.stderr index 54dcdd8957902..fb0b72c000105 100644 --- a/tests/ui/span/E0535.stderr +++ b/tests/ui/span/E0535.stderr @@ -9,7 +9,7 @@ note: valid arguments are `always` or `never` | LL | #[inline(unknown)] | ^^^^^^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[inline(unknown)] LL + #[inline(always|never)] diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-2.rs b/tests/ui/stability-attribute/stability-attribute-sanity-2.rs index de3ea4eaca967..92e300d33d6ec 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity-2.rs +++ b/tests/ui/stability-attribute/stability-attribute-sanity-2.rs @@ -4,7 +4,7 @@ #![stable(feature = "stable_test_feature", since = "1.0.0")] -#[stable(feature = "a", feature = "b", since = "1.0.0")] //~ ERROR multiple 'feature' items +#[stable(feature = "a", feature = "b", since = "1.0.0")] //~ ERROR malformed `stable` attribute input [E0538] fn f1() { } #[stable(feature = "a", sinse = "1.0.0")] //~ ERROR unknown meta item 'sinse' diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr b/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr index 8dbcc6c97efd5..412af87bad698 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr @@ -1,8 +1,14 @@ -error[E0538]: multiple 'feature' items +error[E0538]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity-2.rs:7:1 + | +LL | #[stable(feature = "a", feature = "b", since = "1.0.0")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` + | +note: found `feature` used as a key more than once --> $DIR/stability-attribute-sanity-2.rs:7:25 | LL | #[stable(feature = "a", feature = "b", since = "1.0.0")] - | ^^^^^^^^^^^^^ + | ^^^^^^^ error[E0541]: unknown meta item 'sinse' --> $DIR/stability-attribute-sanity-2.rs:10:25 diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.rs b/tests/ui/stability-attribute/stability-attribute-sanity.rs index f46e35e1a72af..c4c86e12d267e 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.rs +++ b/tests/ui/stability-attribute/stability-attribute-sanity.rs @@ -8,16 +8,16 @@ mod bogus_attribute_types_1 { #[stable(feature = "a", since = "4.4.4", reason)] //~ ERROR unknown meta item 'reason' [E0541] fn f1() { } - #[stable(feature = "a", since)] //~ ERROR expected a quoted string literal [E0539] + #[stable(feature = "a", since)] //~ ERROR malformed `stable` attribute input [E0539] fn f2() { } - #[stable(feature, since = "3.3.3")] //~ ERROR expected a quoted string literal [E0539] + #[stable(feature, since = "3.3.3")] //~ ERROR malformed `stable` attribute input [E0539] fn f3() { } - #[stable(feature = "a", since(b))] //~ ERROR expected a quoted string literal [E0539] + #[stable(feature = "a", since(b))] //~ ERROR malformed `stable` attribute input [E0539] fn f5() { } - #[stable(feature(b), since = "3.3.3")] //~ ERROR expected a quoted string literal [E0539] + #[stable(feature(b), since = "3.3.3")] //~ ERROR malformed `stable` attribute input [E0539] fn f6() { } } diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.stderr b/tests/ui/stability-attribute/stability-attribute-sanity.stderr index 2e2b5b509c896..86284b0c1b816 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity.stderr @@ -4,25 +4,49 @@ error[E0541]: unknown meta item 'reason' LL | #[stable(feature = "a", since = "4.4.4", reason)] | ^^^^^^ expected one of `feature`, `since` -error[E0539]: expected a quoted string literal +error[E0539]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity.rs:11:5 + | +LL | #[stable(feature = "a", since)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` + | +note: expected this to be of the form `since = "..."` --> $DIR/stability-attribute-sanity.rs:11:29 | LL | #[stable(feature = "a", since)] | ^^^^^ -error[E0539]: expected a quoted string literal +error[E0539]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity.rs:14:5 + | +LL | #[stable(feature, since = "3.3.3")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` + | +note: expected this to be of the form `feature = "..."` --> $DIR/stability-attribute-sanity.rs:14:14 | LL | #[stable(feature, since = "3.3.3")] | ^^^^^^^ -error[E0539]: expected a quoted string literal +error[E0539]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity.rs:17:5 + | +LL | #[stable(feature = "a", since(b))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` + | +note: expected this to be of the form `since = "..."` --> $DIR/stability-attribute-sanity.rs:17:29 | LL | #[stable(feature = "a", since(b))] | ^^^^^^^^ -error[E0539]: expected a quoted string literal +error[E0539]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity.rs:20:5 + | +LL | #[stable(feature(b), since = "3.3.3")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` + | +note: expected this to be of the form `feature = "..."` --> $DIR/stability-attribute-sanity.rs:20:14 | LL | #[stable(feature(b), since = "3.3.3")] From 5913a872376f7d0091aaf1c4b1f7664039adb5ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 8 Mar 2025 18:58:05 +0100 Subject: [PATCH 6/7] make error codes reflect reality better --- compiler/rustc_attr_parsing/messages.ftl | 4 - .../src/attributes/confusables.rs | 6 +- .../src/attributes/deprecation.rs | 100 +++++++++--------- .../src/attributes/inline.rs | 4 +- .../rustc_attr_parsing/src/attributes/repr.rs | 1 + compiler/rustc_attr_parsing/src/context.rs | 31 +++++- .../src/session_diagnostics.rs | 49 +++++---- .../src/error_codes/E0534.md | 8 +- .../src/error_codes/E0535.md | 9 +- .../src/error_codes/E0539.md | 29 ++++- .../src/error_codes/E0565.md | 7 +- .../src/error_codes/E0805.md | 26 +++++ compiler/rustc_error_codes/src/lib.rs | 1 + compiler/rustc_parse/src/validate_attr.rs | 9 +- compiler/rustc_passes/src/check_attr.rs | 7 -- tests/ui/attributes/rustc_confusables.stderr | 20 ++-- tests/ui/deprecation/deprecation-sanity.rs | 4 +- .../ui/deprecation/deprecation-sanity.stderr | 73 ++++++------- tests/ui/deprecation/invalid-literal.stderr | 19 ++-- tests/ui/error-codes/E0534.stderr | 22 ---- tests/ui/error-codes/{E0565-2.rs => E0539.rs} | 2 +- tests/ui/error-codes/E0539.stderr | 13 +++ tests/ui/error-codes/{E0534.rs => E0540.rs} | 0 tests/ui/error-codes/E0540.stderr | 19 ++++ tests/ui/error-codes/E0565-1.stderr | 20 +++- tests/ui/error-codes/E0565-2.stderr | 11 -- ...43106-gating-of-builtin-attrs-error.stderr | 20 ++-- tests/ui/force-inlining/invalid.stderr | 32 +++--- tests/ui/invalid/invalid-inline.stderr | 24 ++--- tests/ui/issues/issue-43988.stderr | 48 ++++----- .../lint/unused/unused-attr-duplicate.stderr | 36 +++---- .../genercs-in-path-with-prettry-hir.stdout | 2 +- tests/ui/repr/repr.stderr | 22 ++-- tests/ui/span/{E0535.rs => E0539.rs} | 0 tests/ui/span/{E0535.stderr => E0539.stderr} | 11 +- .../stability-attribute-sanity-2.stderr | 11 +- .../stability-attribute-sanity.stderr | 44 +++----- 37 files changed, 406 insertions(+), 338 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0805.md delete mode 100644 tests/ui/error-codes/E0534.stderr rename tests/ui/error-codes/{E0565-2.rs => E0539.rs} (54%) create mode 100644 tests/ui/error-codes/E0539.stderr rename tests/ui/error-codes/{E0534.rs => E0540.rs} (100%) create mode 100644 tests/ui/error-codes/E0540.stderr delete mode 100644 tests/ui/error-codes/E0565-2.stderr rename tests/ui/span/{E0535.rs => E0539.rs} (100%) rename tests/ui/span/{E0535.stderr => E0539.stderr} (68%) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 70de83f2f7443..b9b386635f630 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -121,10 +121,6 @@ attr_parsing_unsupported_literal_cfg_boolean = literal in `cfg` predicate value must be a boolean attr_parsing_unsupported_literal_cfg_string = literal in `cfg` predicate value must be a string -attr_parsing_unsupported_literal_deprecated_kv_pair = - item in `deprecated` must be a key/value pair -attr_parsing_unsupported_literal_deprecated_string = - literal in `deprecated` value must be a string attr_parsing_unsupported_literal_generic = unsupported literal attr_parsing_unsupported_literal_suggestion = diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index f4505cbc0e1b7..c911908dfb381 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -30,12 +30,12 @@ impl AttributeParser for ConfusablesParser { for param in list.mixed() { let span = param.span(); - let Some(lit) = param.lit() else { - cx.expected_string_literal(span); + let Some(lit) = param.lit().and_then(|i| i.value_str()) else { + cx.expected_string_literal(span, param.lit()); continue; }; - this.confusables.push(lit.symbol); + this.confusables.push(lit); } this.first_span.get_or_insert(cx.attr_span); diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 0983a153efa98..702ad66f57805 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -7,7 +7,6 @@ use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics; -use crate::session_diagnostics::UnsupportedLiteralReason; pub(crate) struct DeprecationParser; @@ -26,13 +25,7 @@ fn get( if let Some(value_str) = v.value_as_str() { Some(value_str) } else { - let lit = v.value_as_lit(); - cx.emit_err(session_diagnostics::UnsupportedLiteral { - span: v.value_span, - reason: UnsupportedLiteralReason::DeprecatedString, - is_bytestr: lit.kind.is_bytestr(), - start_point_span: cx.sess().source_map().start_point(lit.span), - }); + cx.expected_string_literal(v.value_span, Some(&v.value_as_lit())); None } } else { @@ -60,57 +53,60 @@ impl SingleAttributeParser for DeprecationParser { let is_rustc = features.staged_api(); - if let Some(value) = args.name_value() - && let Some(value_str) = value.value_as_str() - { - note = Some(value_str) - } else if let Some(list) = args.list() { - for param in list.mixed() { - let param_span = param.span(); - let Some(param) = param.meta_item() else { - cx.emit_err(session_diagnostics::UnsupportedLiteral { - span: param_span, - reason: UnsupportedLiteralReason::DeprecatedKvPair, - is_bytestr: false, - start_point_span: cx.sess().source_map().start_point(param_span), - }); - return None; - }; + match args { + ArgParser::NoArgs => { + // ok + } + ArgParser::List(list) => { + for param in list.mixed() { + let Some(param) = param.meta_item() else { + cx.unexpected_literal(param.span()); + return None; + }; - let ident_name = param.path().word_sym(); + let ident_name = param.path().word_sym(); - match ident_name { - Some(name @ sym::since) => { - since = Some(get(cx, name, param_span, param.args(), &since)?); - } - Some(name @ sym::note) => { - note = Some(get(cx, name, param_span, param.args(), ¬e)?); - } - Some(name @ sym::suggestion) => { - if !features.deprecated_suggestion() { - cx.emit_err(session_diagnostics::DeprecatedItemSuggestion { - span: param_span, - is_nightly: cx.sess().is_nightly_build(), - details: (), - }); + match ident_name { + Some(name @ sym::since) => { + since = Some(get(cx, name, param.span(), param.args(), &since)?); + } + Some(name @ sym::note) => { + note = Some(get(cx, name, param.span(), param.args(), ¬e)?); } + Some(name @ sym::suggestion) => { + if !features.deprecated_suggestion() { + cx.emit_err(session_diagnostics::DeprecatedItemSuggestion { + span: param.span(), + is_nightly: cx.sess().is_nightly_build(), + details: (), + }); + } - suggestion = Some(get(cx, name, param_span, param.args(), &suggestion)?); - } - _ => { - cx.unknown_key( - param_span, - param.path().to_string(), - if features.deprecated_suggestion() { - &["since", "note", "suggestion"] - } else { - &["since", "note"] - }, - ); - return None; + suggestion = + Some(get(cx, name, param.span(), param.args(), &suggestion)?); + } + _ => { + cx.unknown_key( + param.span(), + param.path().to_string(), + if features.deprecated_suggestion() { + &["since", "note", "suggestion"] + } else { + &["since", "note"] + }, + ); + return None; + } } } } + ArgParser::NameValue(v) => { + let Some(value) = v.value_as_str() else { + cx.expected_string_literal(v.value_span, Some(v.value_as_lit())); + return None; + }; + note = Some(value); + } } let since = if let Some(since) = since { diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index 75ae1d6a6c173..25efc3ae49b9d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -73,7 +73,7 @@ impl SingleAttributeParser for RustcForceInlineParser { }; let Some(reason) = l.lit().and_then(|i| i.kind.str()) else { - cx.expected_string_literal(l.span()); + cx.expected_string_literal(l.span(), l.lit()); return None; }; @@ -81,7 +81,7 @@ impl SingleAttributeParser for RustcForceInlineParser { } ArgParser::NameValue(v) => { let Some(reason) = v.value_as_str() else { - cx.expected_string_literal(v.value_span); + cx.expected_string_literal(v.value_span, Some(v.value_as_lit())); return None; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 6fb618541e392..ae9e7871874d6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -34,6 +34,7 @@ impl CombineAttributeParser for ReprParser { let mut reprs = Vec::new(); let Some(list) = args.list() else { + cx.expected_list(cx.attr_span); return reprs; }; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 87f2f609ef821..56defacc84d08 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -5,8 +5,7 @@ use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; use private::Sealed; -use rustc_ast as ast; -use rustc_ast::NodeId; +use rustc_ast::{self as ast, MetaItemLit, NodeId}; use rustc_attr_data_structures::AttributeKind; use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind}; use rustc_errors::{DiagCtxtHandle, Diagnostic}; @@ -198,13 +197,25 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { self.emit_err(UnknownMetaItem { span, item: found, expected: options }) } - pub(crate) fn expected_string_literal(&self, span: Span) -> ErrorGuaranteed { + /// error that a string literal was expected. + /// You can optionally give the literal you did find (which you found not to be a string literal) + /// which can make better errors. For example, if the literal was a byte string it will suggest + /// removing the `b` prefix. + pub(crate) fn expected_string_literal( + &self, + span: Span, + actual_literal: Option<&MetaItemLit>, + ) -> ErrorGuaranteed { self.emit_err(AttributeParseError { span, attr_span: self.attr_span, template: self.template.clone(), attribute: self.attr_path.clone(), - reason: AttributeParseErrorReason::ExpectedStringLiteral, + reason: AttributeParseErrorReason::ExpectedStringLiteral { + byte_string: actual_literal.and_then(|i| { + i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span)) + }), + }, }) } @@ -241,6 +252,18 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } + /// an error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser) + /// was expected *not* to be a literal, but instead a meta item. + pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::UnexpectedLiteral, + }) + } + pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed { self.emit_err(AttributeParseError { span, diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 3d865c1d14e7f..57ac92a0ca190 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -16,8 +16,6 @@ pub(crate) enum UnsupportedLiteralReason { Generic, CfgString, CfgBoolean, - DeprecatedString, - DeprecatedKvPair, } #[derive(Diagnostic)] @@ -190,6 +188,7 @@ pub(crate) struct InvalidReprHintNoValue { } /// Error code: E0565 +// FIXME(jdonszelmann): slowly phased out pub(crate) struct UnsupportedLiteral { pub span: Span, pub reason: UnsupportedLiteralReason, @@ -212,12 +211,6 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral { UnsupportedLiteralReason::CfgBoolean => { fluent::attr_parsing_unsupported_literal_cfg_boolean } - UnsupportedLiteralReason::DeprecatedString => { - fluent::attr_parsing_unsupported_literal_deprecated_string - } - UnsupportedLiteralReason::DeprecatedKvPair => { - fluent::attr_parsing_unsupported_literal_deprecated_kv_pair - } }, ); diag.span(self.span); @@ -473,9 +466,10 @@ pub(crate) struct UnrecognizedReprHint { } pub(crate) enum AttributeParseErrorReason { - ExpectedStringLiteral, + ExpectedStringLiteral { byte_string: Option }, ExpectedSingleArgument, ExpectedList, + UnexpectedLiteral, ExpectedNameValue(Option), DuplicateKey(Symbol), ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool }, @@ -497,27 +491,44 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { diag.span(self.attr_span); diag.code(E0539); match self.reason { - AttributeParseErrorReason::ExpectedStringLiteral => { - diag.span_note(self.span, "expected a string literal here"); + AttributeParseErrorReason::ExpectedStringLiteral { byte_string } => { + if let Some(start_point_span) = byte_string { + diag.span_suggestion( + start_point_span, + fluent::attr_parsing_unsupported_literal_suggestion, + "", + Applicability::MaybeIncorrect, + ); + diag.note("expected a normal string literal, not a byte string literal"); + + return diag; + } else { + diag.span_label(self.span, "expected a string literal here"); + } } AttributeParseErrorReason::ExpectedSingleArgument => { - diag.span_note(self.span, "expected a single argument here"); + diag.span_label(self.span, "expected a single argument here"); + diag.code(E0805); } AttributeParseErrorReason::ExpectedList => { - diag.span_note(self.span, "expected this to be a list"); + diag.span_label(self.span, "expected this to be a list"); } AttributeParseErrorReason::DuplicateKey(key) => { - diag.span_note(self.span, format!("found `{key}` used as a key more than once")); + diag.span_label(self.span, format!("found `{key}` used as a key more than once")); diag.code(E0538); } + AttributeParseErrorReason::UnexpectedLiteral => { + diag.span_label(self.span, format!("didn't expect a literal here")); + diag.code(E0565); + } AttributeParseErrorReason::ExpectedNameValue(None) => { - diag.span_note( + diag.span_label( self.span, format!("expected this to be of the form `{name} = \"...\"`"), ); } AttributeParseErrorReason::ExpectedNameValue(Some(name)) => { - diag.span_note( + diag.span_label( self.span, format!("expected this to be of the form `{name} = \"...\"`"), ); @@ -527,13 +538,13 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { match possibilities.as_slice() { &[] => {} &[x] => { - diag.span_note( + diag.span_label( self.span, format!("the only valid argument here is {quote}{x}{quote}"), ); } [first, second] => { - diag.span_note(self.span, format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}")); + diag.span_label(self.span, format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}")); } [first @ .., second_to_last, last] => { let mut res = String::new(); @@ -544,7 +555,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { "{quote}{second_to_last}{quote} or {quote}{last}{quote}" )); - diag.span_note(self.span, format!("valid arguments are {res}")); + diag.span_label(self.span, format!("valid arguments are {res}")); } } } diff --git a/compiler/rustc_error_codes/src/error_codes/E0534.md b/compiler/rustc_error_codes/src/error_codes/E0534.md index 1ca9411b8d4c2..023c38c730cd4 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0534.md +++ b/compiler/rustc_error_codes/src/error_codes/E0534.md @@ -1,8 +1,14 @@ +#### Note: this error code is no longer emitted by the compiler + +This is because it was too specific to the `inline` attribute. +Similar diagnostics occur for other attributes too. +The example here will now emit `E0805` + The `inline` attribute was malformed. Erroneous code example: -```compile_fail,E0534 +```compile_fail,E0805 #[inline()] // error: expected one argument pub fn something() {} diff --git a/compiler/rustc_error_codes/src/error_codes/E0535.md b/compiler/rustc_error_codes/src/error_codes/E0535.md index 0cf3118b02c5c..93e2ba5382673 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0535.md +++ b/compiler/rustc_error_codes/src/error_codes/E0535.md @@ -1,8 +1,13 @@ -An unknown argument was given to the `inline` attribute. +#### Note: this error code is no longer emitted by the compiler + +This is because it was too specific to the `inline` attribute. +Similar diagnostics occur for other attributes too. +The example here will now emit `E0539` + Erroneous code example: -```compile_fail,E0535 +```compile_fail,E0539 #[inline(unknown)] // error: invalid argument pub fn something() {} diff --git a/compiler/rustc_error_codes/src/error_codes/E0539.md b/compiler/rustc_error_codes/src/error_codes/E0539.md index 6b2e23ba2d8c4..c76b60ac108db 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0539.md +++ b/compiler/rustc_error_codes/src/error_codes/E0539.md @@ -24,8 +24,7 @@ struct Stable; const fn stable_fn() {} ``` -Meta items are the key-value pairs inside of an attribute. -To fix these issues you need to give required key-value pairs. +To fix the above example, you can write the following: ``` #![feature(staged_api)] @@ -49,3 +48,29 @@ struct Stable; #[rustc_const_stable(feature = "stable_fn", since = "1.39.0")] // ok! const fn stable_fn() {} ``` + +Several causes of this are, +an attribute may have expected you to give a list but you gave a +`name = value` pair: + +```compile_fail,E0539 +// wrong, should be `#[repr(C)]` +#[repr = "C"] +struct Foo {} +``` + +Or a `name = value` pair, but you gave a list: + +```compile_fail,E0539 +// wrong, should be `note = "reason"` +#[deprecated(since = "1.0.0", note("reason"))] +struct Foo {} +``` + +Or it expected some specific word but you gave an unexpected one: + +```compile_fail,E0539 +// should be `always` or `never` +#[inline(maybe_if_you_feel_like_it)] +fn foo() {} +``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0565.md b/compiler/rustc_error_codes/src/error_codes/E0565.md index d5bba941c1dd2..34152eb7cfe0d 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0565.md +++ b/compiler/rustc_error_codes/src/error_codes/E0565.md @@ -9,10 +9,9 @@ struct Repr {} fn main() {} ``` -Literals in attributes are new and largely unsupported in built-in attributes. -Work to support literals where appropriate is ongoing. Try using an unquoted -name instead: - +Not all attributes support literals in their input, +and in some cases they expect an identifier instead. +That would be the solution in the case of `repr`: ``` #[repr(C)] // ok! struct Repr {} diff --git a/compiler/rustc_error_codes/src/error_codes/E0805.md b/compiler/rustc_error_codes/src/error_codes/E0805.md new file mode 100644 index 0000000000000..b1ed3a11d4824 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0805.md @@ -0,0 +1,26 @@ +An attribute was given an invalid number of arguments + +Erroneous code example: + +```compile_fail,E0805 +#[inline()] // error! should either have a single argument, or no parentheses +fn foo() {} + +#[inline(always, never)] // error! should have only one argument, not two +fn bar() {} +``` + +To fix this, either give the right number of arguments the attribute needs. +In the case of inline, this could be none at all: + +``` +#[inline] +fn foo() {} +``` + +or only one: + +``` +#[inline(always)] +fn foo() {} +``` diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 2488d870899ce..6f5e4829802e9 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -547,6 +547,7 @@ E0801: 0801, E0802: 0802, E0803: 0803, E0804: 0804, +E0805: 0805, ); ) } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 2296ec1043256..b3096e46b09ca 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -283,7 +283,14 @@ fn emit_malformed_attribute( template: AttributeTemplate, ) { // attrs with new parsers are locally validated so excluded here - if matches!(name, sym::inline | sym::rustc_force_inline | sym::rustc_confusables) { + if matches!( + name, + sym::inline + | sym::rustc_force_inline + | sym::rustc_confusables + | sym::repr + | sym::deprecated + ) { return; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 59f17ac4dcf74..af83b80f9374c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -728,13 +728,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } } - // FIXME(#80564): We permit struct fields, match arms and macro defs to have an - // `#[naked]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to be compatible - // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "naked") - } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { attr_span: attr.span(), diff --git a/tests/ui/attributes/rustc_confusables.stderr b/tests/ui/attributes/rustc_confusables.stderr index be16da2f873c7..3ed4efeb4dbc6 100644 --- a/tests/ui/attributes/rustc_confusables.stderr +++ b/tests/ui/attributes/rustc_confusables.stderr @@ -7,26 +7,20 @@ LL | #[rustc_confusables()] error[E0539]: malformed `rustc_confusables` attribute input --> $DIR/rustc_confusables.rs:34:5 | -LL | #[rustc_confusables] - | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` - | -note: expected this to be a list - --> $DIR/rustc_confusables.rs:34:5 - | LL | #[rustc_confusables] | ^^^^^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` error[E0539]: malformed `rustc_confusables` attribute input --> $DIR/rustc_confusables.rs:39:5 | LL | #[rustc_confusables(invalid_meta_item)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` - | -note: expected a string literal here - --> $DIR/rustc_confusables.rs:39:25 - | -LL | #[rustc_confusables(invalid_meta_item)] - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^-----------------^^ + | | | + | | expected a string literal here + | help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` error: attribute should be applied to an inherent method --> $DIR/rustc_confusables.rs:45:1 diff --git a/tests/ui/deprecation/deprecation-sanity.rs b/tests/ui/deprecation/deprecation-sanity.rs index e40b017378a6c..80198ab81968f 100644 --- a/tests/ui/deprecation/deprecation-sanity.rs +++ b/tests/ui/deprecation/deprecation-sanity.rs @@ -16,10 +16,10 @@ mod bogus_attribute_types_1 { #[deprecated(since(b), note = "a")] //~ ERROR malformed `deprecated` attribute input [E0539] fn f6() { } - #[deprecated(note = b"test")] //~ ERROR literal in `deprecated` value must be a string + #[deprecated(note = b"test")] //~ ERROR malformed `deprecated` attribute input [E0539] fn f7() { } - #[deprecated("test")] //~ ERROR item in `deprecated` must be a key/value pair + #[deprecated("test")] //~ ERROR malformed `deprecated` attribute input [E0565] fn f8() { } } diff --git a/tests/ui/deprecation/deprecation-sanity.stderr b/tests/ui/deprecation/deprecation-sanity.stderr index 8854ebb70d200..f1b4697485cfc 100644 --- a/tests/ui/deprecation/deprecation-sanity.stderr +++ b/tests/ui/deprecation/deprecation-sanity.stderr @@ -8,13 +8,10 @@ error[E0539]: malformed `deprecated` attribute input --> $DIR/deprecation-sanity.rs:7:5 | LL | #[deprecated(since = "a", note)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^----^^ + | | + | expected this to be of the form `note = "..."` | -note: expected this to be of the form `note = "..."` - --> $DIR/deprecation-sanity.rs:7:31 - | -LL | #[deprecated(since = "a", note)] - | ^^^^ help: try changing it to one of the following valid forms of the attribute | LL - #[deprecated(since = "a", note)] @@ -31,13 +28,10 @@ error[E0539]: malformed `deprecated` attribute input --> $DIR/deprecation-sanity.rs:10:5 | LL | #[deprecated(since, note = "a")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: expected this to be of the form `since = "..."` - --> $DIR/deprecation-sanity.rs:10:18 + | ^^^^^^^^^^^^^-----^^^^^^^^^^^^^^ + | | + | expected this to be of the form `since = "..."` | -LL | #[deprecated(since, note = "a")] - | ^^^^^ help: try changing it to one of the following valid forms of the attribute | LL - #[deprecated(since, note = "a")] @@ -54,13 +48,10 @@ error[E0539]: malformed `deprecated` attribute input --> $DIR/deprecation-sanity.rs:13:5 | LL | #[deprecated(since = "a", note(b))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: expected this to be of the form `note = "..."` - --> $DIR/deprecation-sanity.rs:13:31 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^ + | | + | expected this to be of the form `note = "..."` | -LL | #[deprecated(since = "a", note(b))] - | ^^^^^^^ help: try changing it to one of the following valid forms of the attribute | LL - #[deprecated(since = "a", note(b))] @@ -77,13 +68,10 @@ error[E0539]: malformed `deprecated` attribute input --> $DIR/deprecation-sanity.rs:16:5 | LL | #[deprecated(since(b), note = "a")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^--------^^^^^^^^^^^^^^ + | | + | expected this to be of the form `since = "..."` | -note: expected this to be of the form `since = "..."` - --> $DIR/deprecation-sanity.rs:16:18 - | -LL | #[deprecated(since(b), note = "a")] - | ^^^^^^^^ help: try changing it to one of the following valid forms of the attribute | LL - #[deprecated(since(b), note = "a")] @@ -96,19 +84,35 @@ LL - #[deprecated(since(b), note = "a")] LL + #[deprecated] | -error[E0565]: literal in `deprecated` value must be a string - --> $DIR/deprecation-sanity.rs:19:25 +error[E0539]: malformed `deprecated` attribute input + --> $DIR/deprecation-sanity.rs:19:5 | LL | #[deprecated(note = b"test")] - | -^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^-^^^^^^^^ | | | help: consider removing the prefix + | + = note: expected a normal string literal, not a byte string literal -error[E0565]: item in `deprecated` must be a key/value pair - --> $DIR/deprecation-sanity.rs:22:18 +error[E0565]: malformed `deprecated` attribute input + --> $DIR/deprecation-sanity.rs:22:5 | LL | #[deprecated("test")] - | ^^^^^^ + | ^^^^^^^^^^^^^------^^ + | | + | didn't expect a literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[deprecated("test")] +LL + #[deprecated = "reason"] + | +LL - #[deprecated("test")] +LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] + | +LL - #[deprecated("test")] +LL + #[deprecated] + | error: multiple `deprecated` attributes --> $DIR/deprecation-sanity.rs:27:1 @@ -126,13 +130,10 @@ error[E0538]: malformed `deprecated` attribute input --> $DIR/deprecation-sanity.rs:30:1 | LL | #[deprecated(since = "a", since = "b", note = "c")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^^^^^^^^ + | | + | found `since` used as a key more than once | -note: found `since` used as a key more than once - --> $DIR/deprecation-sanity.rs:30:27 - | -LL | #[deprecated(since = "a", since = "b", note = "c")] - | ^^^^^ help: try changing it to one of the following valid forms of the attribute | LL - #[deprecated(since = "a", since = "b", note = "c")] diff --git a/tests/ui/deprecation/invalid-literal.stderr b/tests/ui/deprecation/invalid-literal.stderr index cbe1fcca0238b..6f25aebc315ee 100644 --- a/tests/ui/deprecation/invalid-literal.stderr +++ b/tests/ui/deprecation/invalid-literal.stderr @@ -1,20 +1,13 @@ -error: malformed `deprecated` attribute input +error[E0539]: malformed `deprecated` attribute input --> $DIR/invalid-literal.rs:1:1 | LL | #[deprecated = b"test"] - | ^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[deprecated = b"test"] -LL + #[deprecated = "reason"] - | -LL - #[deprecated = b"test"] -LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] - | -LL - #[deprecated = b"test"] -LL + #[deprecated] + | ^^^^^^^^^^^^^^^-^^^^^^^ + | | + | help: consider removing the prefix | + = note: expected a normal string literal, not a byte string literal error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/error-codes/E0534.stderr b/tests/ui/error-codes/E0534.stderr deleted file mode 100644 index de97ef18b7356..0000000000000 --- a/tests/ui/error-codes/E0534.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0539]: malformed `inline` attribute input - --> $DIR/E0534.rs:1:1 - | -LL | #[inline()] - | ^^^^^^^^^^^ - | -note: expected a single argument here - --> $DIR/E0534.rs:1:9 - | -LL | #[inline()] - | ^^ -help: try changing it to one of the following valid forms of the attribute - | -LL | #[inline(always|never)] - | ++++++++++++ -LL - #[inline()] -LL + #[inline] - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/error-codes/E0565-2.rs b/tests/ui/error-codes/E0539.rs similarity index 54% rename from tests/ui/error-codes/E0565-2.rs rename to tests/ui/error-codes/E0539.rs index 0319ecb11f9e6..0e2c537f47307 100644 --- a/tests/ui/error-codes/E0565-2.rs +++ b/tests/ui/error-codes/E0539.rs @@ -1,5 +1,5 @@ // repr currently doesn't support literals -#[deprecated(since = b"1.29", note = "hi")] //~ ERROR E0565 +#[deprecated(since = b"1.29", note = "hi")] //~ ERROR E0539 struct A { } fn main() { } diff --git a/tests/ui/error-codes/E0539.stderr b/tests/ui/error-codes/E0539.stderr new file mode 100644 index 0000000000000..18ed1c23b40ab --- /dev/null +++ b/tests/ui/error-codes/E0539.stderr @@ -0,0 +1,13 @@ +error[E0539]: malformed `deprecated` attribute input + --> $DIR/E0539.rs:2:1 + | +LL | #[deprecated(since = b"1.29", note = "hi")] + | ^^^^^^^^^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider removing the prefix + | + = note: expected a normal string literal, not a byte string literal + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/error-codes/E0534.rs b/tests/ui/error-codes/E0540.rs similarity index 100% rename from tests/ui/error-codes/E0534.rs rename to tests/ui/error-codes/E0540.rs diff --git a/tests/ui/error-codes/E0540.stderr b/tests/ui/error-codes/E0540.stderr new file mode 100644 index 0000000000000..3e5f408feb551 --- /dev/null +++ b/tests/ui/error-codes/E0540.stderr @@ -0,0 +1,19 @@ +error[E0805]: malformed `inline` attribute input + --> $DIR/E0540.rs:1:1 + | +LL | #[inline()] + | ^^^^^^^^--^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL | #[inline(always|never)] + | ++++++++++++ +LL - #[inline()] +LL + #[inline] + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0805`. diff --git a/tests/ui/error-codes/E0565-1.stderr b/tests/ui/error-codes/E0565-1.stderr index 806eed2a632f8..6277e6400d77f 100644 --- a/tests/ui/error-codes/E0565-1.stderr +++ b/tests/ui/error-codes/E0565-1.stderr @@ -1,8 +1,22 @@ -error[E0565]: item in `deprecated` must be a key/value pair - --> $DIR/E0565-1.rs:2:14 +error[E0565]: malformed `deprecated` attribute input + --> $DIR/E0565-1.rs:2:1 | LL | #[deprecated("since")] - | ^^^^^^^ + | ^^^^^^^^^^^^^-------^^ + | | + | didn't expect a literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[deprecated("since")] +LL + #[deprecated = "reason"] + | +LL - #[deprecated("since")] +LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] + | +LL - #[deprecated("since")] +LL + #[deprecated] + | error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0565-2.stderr b/tests/ui/error-codes/E0565-2.stderr deleted file mode 100644 index 42199351c3da2..0000000000000 --- a/tests/ui/error-codes/E0565-2.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0565]: literal in `deprecated` value must be a string - --> $DIR/E0565-2.rs:2:22 - | -LL | #[deprecated(since = b"1.29", note = "hi")] - | -^^^^^^ - | | - | help: consider removing the prefix - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0565`. diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr index a9ef0bbc6e78b..1620bf7292293 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr @@ -8,16 +8,6 @@ LL | #![rustc_main] = note: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable = note: the `#[rustc_main]` attribute is used internally to specify test entry point function -error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]` - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5 - | -LL | #[inline = "2100"] fn f() { } - | ^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - = note: `#[deny(ill_formed_attribute_input)]` on by default - error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:1 | @@ -314,6 +304,16 @@ error[E0517]: attribute should be applied to a struct, enum, or union LL | #[repr(Rust)] impl S { } | ^^^^ ---------- not a struct, enum, or union +error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]` + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5 + | +LL | #[inline = "2100"] fn f() { } + | ^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(ill_formed_attribute_input)]` on by default + error: aborting due to 38 previous errors Some errors have detailed explanations: E0517, E0518, E0658. diff --git a/tests/ui/force-inlining/invalid.stderr b/tests/ui/force-inlining/invalid.stderr index a12f633b3f26d..3b3da00ae88c7 100644 --- a/tests/ui/force-inlining/invalid.stderr +++ b/tests/ui/force-inlining/invalid.stderr @@ -4,17 +4,14 @@ error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed LL | fn barqux(#[rustc_force_inline] _x: u32) {} | ^^^^^^^^^^^^^^^^^^^^^ -error[E0539]: malformed `rustc_force_inline` attribute input +error[E0805]: malformed `rustc_force_inline` attribute input --> $DIR/invalid.rs:15:1 | LL | #[rustc_force_inline(bar, baz)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: expected a single argument here - --> $DIR/invalid.rs:15:21 + | ^^^^^^^^^^^^^^^^^^^^----------^ + | | + | expected a single argument here | -LL | #[rustc_force_inline(bar, baz)] - | ^^^^^^^^^^ help: try changing it to one of the following valid forms of the attribute | LL - #[rustc_force_inline(bar, baz)] @@ -31,13 +28,10 @@ error[E0539]: malformed `rustc_force_inline` attribute input --> $DIR/invalid.rs:20:1 | LL | #[rustc_force_inline(2)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: expected a string literal here - --> $DIR/invalid.rs:20:22 + | ^^^^^^^^^^^^^^^^^^^^^-^^ + | | + | expected a string literal here | -LL | #[rustc_force_inline(2)] - | ^ help: try changing it to one of the following valid forms of the attribute | LL - #[rustc_force_inline(2)] @@ -54,13 +48,10 @@ error[E0539]: malformed `rustc_force_inline` attribute input --> $DIR/invalid.rs:25:1 | LL | #[rustc_force_inline = 2] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: expected a string literal here - --> $DIR/invalid.rs:25:24 + | ^^^^^^^^^^^^^^^^^^^^^^^-^ + | | + | expected a string literal here | -LL | #[rustc_force_inline = 2] - | ^ help: try changing it to one of the following valid forms of the attribute | LL - #[rustc_force_inline = 2] @@ -392,4 +383,5 @@ LL | fn foo(); error: aborting due to 37 previous errors -For more information about this error, try `rustc --explain E0539`. +Some errors have detailed explanations: E0539, E0805. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/invalid/invalid-inline.stderr b/tests/ui/invalid/invalid-inline.stderr index 8a230351d324f..54e6b2b540824 100644 --- a/tests/ui/invalid/invalid-inline.stderr +++ b/tests/ui/invalid/invalid-inline.stderr @@ -1,14 +1,11 @@ -error[E0539]: malformed `inline` attribute input +error[E0805]: malformed `inline` attribute input --> $DIR/invalid-inline.rs:3:1 | LL | #[inline(please,no)] - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^-----------^ + | | + | expected a single argument here | -note: expected a single argument here - --> $DIR/invalid-inline.rs:3:9 - | -LL | #[inline(please,no)] - | ^^^^^^^^^^^ help: try changing it to one of the following valid forms of the attribute | LL - #[inline(please,no)] @@ -18,17 +15,14 @@ LL - #[inline(please,no)] LL + #[inline] | -error[E0539]: malformed `inline` attribute input +error[E0805]: malformed `inline` attribute input --> $DIR/invalid-inline.rs:7:1 | LL | #[inline()] - | ^^^^^^^^^^^ + | ^^^^^^^^--^ + | | + | expected a single argument here | -note: expected a single argument here - --> $DIR/invalid-inline.rs:7:9 - | -LL | #[inline()] - | ^^ help: try changing it to one of the following valid forms of the attribute | LL | #[inline(always|never)] @@ -39,4 +33,4 @@ LL + #[inline] error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0539`. +For more information about this error, try `rustc --explain E0805`. diff --git a/tests/ui/issues/issue-43988.stderr b/tests/ui/issues/issue-43988.stderr index 8e731db6f2e39..bd4eb8bbed373 100644 --- a/tests/ui/issues/issue-43988.stderr +++ b/tests/ui/issues/issue-43988.stderr @@ -1,26 +1,11 @@ -error: malformed `repr` attribute input - --> $DIR/issue-43988.rs:24:5 - | -LL | #[repr] - | ^^^^^^^ help: must be of the form: `#[repr(C)]` - -error: malformed `repr` attribute input - --> $DIR/issue-43988.rs:34:14 - | -LL | let _z = #[repr] 1; - | ^^^^^^^ help: must be of the form: `#[repr(C)]` - error[E0539]: malformed `inline` attribute input --> $DIR/issue-43988.rs:10:5 | LL | #[inline(XYZ)] - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^---^^ + | | + | valid arguments are `always` or `never` | -note: valid arguments are `always` or `never` - --> $DIR/issue-43988.rs:10:14 - | -LL | #[inline(XYZ)] - | ^^^ help: try changing it to one of the following valid forms of the attribute | LL - #[inline(XYZ)] @@ -46,17 +31,23 @@ LL | #[repr(something_not_real)] | = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` +error[E0539]: malformed `repr` attribute input + --> $DIR/issue-43988.rs:24:5 + | +LL | #[repr] + | ^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[repr(C)]` + error[E0539]: malformed `inline` attribute input --> $DIR/issue-43988.rs:30:5 | LL | #[inline(ABC)] - | ^^^^^^^^^^^^^^ - | -note: valid arguments are `always` or `never` - --> $DIR/issue-43988.rs:30:14 + | ^^^^^^^^^---^^ + | | + | valid arguments are `always` or `never` | -LL | #[inline(ABC)] - | ^^^ help: try changing it to one of the following valid forms of the attribute | LL - #[inline(ABC)] @@ -66,6 +57,15 @@ LL - #[inline(ABC)] LL + #[inline] | +error[E0539]: malformed `repr` attribute input + --> $DIR/issue-43988.rs:34:14 + | +LL | let _z = #[repr] 1; + | ^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[repr(C)]` + error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43988.rs:5:5 | diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 5ea623a713e85..e1c45e832af3f 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -1,21 +1,3 @@ -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:74:1 - | -LL | #[inline(never)] - | ^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:73:1 - | -LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -note: the lint level is defined here - --> $DIR/unused-attr-duplicate.rs:12:9 - | -LL | #![deny(unused_attributes)] - | ^^^^^^^^^^^^^^^^^ - error: unused attribute --> $DIR/unused-attr-duplicate.rs:33:1 | @@ -27,6 +9,11 @@ note: attribute also specified here | LL | #[no_link] | ^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/unused-attr-duplicate.rs:12:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ error: unused attribute --> $DIR/unused-attr-duplicate.rs:37:1 @@ -289,5 +276,18 @@ note: attribute also specified here LL | #[macro_export] | ^^^^^^^^^^^^^^^ +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:74:1 + | +LL | #[inline(never)] + | ^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:73:1 + | +LL | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + error: aborting due to 23 previous errors diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout index 834954d8dc0cd..7c41225f95e67 100644 --- a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout +++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout @@ -8,7 +8,7 @@ extern crate std; // issue#97006 macro_rules! m { ($attr_path: path) => { #[$attr_path] fn f() {} } } -#[attr="Inline(Hint)")] +#[attr = Inline(Hint)] fn f() { } fn main() { } diff --git a/tests/ui/repr/repr.stderr b/tests/ui/repr/repr.stderr index e0bec666381cf..f3b11398eaa41 100644 --- a/tests/ui/repr/repr.stderr +++ b/tests/ui/repr/repr.stderr @@ -1,20 +1,30 @@ -error: malformed `repr` attribute input +error[E0539]: malformed `repr` attribute input --> $DIR/repr.rs:1:1 | LL | #[repr] - | ^^^^^^^ help: must be of the form: `#[repr(C)]` + | ^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[repr(C)]` -error: malformed `repr` attribute input +error[E0539]: malformed `repr` attribute input --> $DIR/repr.rs:4:1 | LL | #[repr = "B"] - | ^^^^^^^^^^^^^ help: must be of the form: `#[repr(C)]` + | ^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[repr(C)]` -error: malformed `repr` attribute input +error[E0539]: malformed `repr` attribute input --> $DIR/repr.rs:7:1 | LL | #[repr = "C"] - | ^^^^^^^^^^^^^ help: must be of the form: `#[repr(C)]` + | ^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[repr(C)]` error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/span/E0535.rs b/tests/ui/span/E0539.rs similarity index 100% rename from tests/ui/span/E0535.rs rename to tests/ui/span/E0539.rs diff --git a/tests/ui/span/E0535.stderr b/tests/ui/span/E0539.stderr similarity index 68% rename from tests/ui/span/E0535.stderr rename to tests/ui/span/E0539.stderr index fb0b72c000105..01f091a26764f 100644 --- a/tests/ui/span/E0535.stderr +++ b/tests/ui/span/E0539.stderr @@ -1,14 +1,11 @@ error[E0539]: malformed `inline` attribute input - --> $DIR/E0535.rs:1:1 + --> $DIR/E0539.rs:1:1 | LL | #[inline(unknown)] - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^-------^^ + | | + | valid arguments are `always` or `never` | -note: valid arguments are `always` or `never` - --> $DIR/E0535.rs:1:10 - | -LL | #[inline(unknown)] - | ^^^^^^^ help: try changing it to one of the following valid forms of the attribute | LL - #[inline(unknown)] diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr b/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr index 412af87bad698..5b35a51cad729 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr @@ -2,13 +2,10 @@ error[E0538]: malformed `stable` attribute input --> $DIR/stability-attribute-sanity-2.rs:7:1 | LL | #[stable(feature = "a", feature = "b", since = "1.0.0")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` - | -note: found `feature` used as a key more than once - --> $DIR/stability-attribute-sanity-2.rs:7:25 - | -LL | #[stable(feature = "a", feature = "b", since = "1.0.0")] - | ^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^-------^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | found `feature` used as a key more than once + | help: must be of the form: `#[stable(feature = "name", since = "version")]` error[E0541]: unknown meta item 'sinse' --> $DIR/stability-attribute-sanity-2.rs:10:25 diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.stderr b/tests/ui/stability-attribute/stability-attribute-sanity.stderr index 86284b0c1b816..ae948237d7edf 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity.stderr @@ -8,49 +8,37 @@ error[E0539]: malformed `stable` attribute input --> $DIR/stability-attribute-sanity.rs:11:5 | LL | #[stable(feature = "a", since)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` - | -note: expected this to be of the form `since = "..."` - --> $DIR/stability-attribute-sanity.rs:11:29 - | -LL | #[stable(feature = "a", since)] - | ^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^-----^^ + | | | + | | expected this to be of the form `since = "..."` + | help: must be of the form: `#[stable(feature = "name", since = "version")]` error[E0539]: malformed `stable` attribute input --> $DIR/stability-attribute-sanity.rs:14:5 | LL | #[stable(feature, since = "3.3.3")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` - | -note: expected this to be of the form `feature = "..."` - --> $DIR/stability-attribute-sanity.rs:14:14 - | -LL | #[stable(feature, since = "3.3.3")] - | ^^^^^^^ + | ^^^^^^^^^-------^^^^^^^^^^^^^^^^^^^ + | | | + | | expected this to be of the form `feature = "..."` + | help: must be of the form: `#[stable(feature = "name", since = "version")]` error[E0539]: malformed `stable` attribute input --> $DIR/stability-attribute-sanity.rs:17:5 | LL | #[stable(feature = "a", since(b))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` - | -note: expected this to be of the form `since = "..."` - --> $DIR/stability-attribute-sanity.rs:17:29 - | -LL | #[stable(feature = "a", since(b))] - | ^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^--------^^ + | | | + | | expected this to be of the form `since = "..."` + | help: must be of the form: `#[stable(feature = "name", since = "version")]` error[E0539]: malformed `stable` attribute input --> $DIR/stability-attribute-sanity.rs:20:5 | LL | #[stable(feature(b), since = "3.3.3")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` - | -note: expected this to be of the form `feature = "..."` - --> $DIR/stability-attribute-sanity.rs:20:14 - | -LL | #[stable(feature(b), since = "3.3.3")] - | ^^^^^^^^^^ + | ^^^^^^^^^----------^^^^^^^^^^^^^^^^^^^ + | | | + | | expected this to be of the form `feature = "..."` + | help: must be of the form: `#[stable(feature = "name", since = "version")]` error[E0546]: missing 'feature' --> $DIR/stability-attribute-sanity.rs:25:5 From f50c732f747801bce8065b7bc22e461c950230d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 10 Jun 2025 08:48:56 +0200 Subject: [PATCH 7/7] fix clippy --- .../rustc_attr_data_structures/src/attributes.rs | 16 +++++----------- .../clippy_lints/src/attrs/inline_always.rs | 2 +- .../clippy_lints/src/inline_fn_without_body.rs | 2 +- .../clippy/clippy_lints/src/missing_inline.rs | 2 +- .../clippy_lints/src/pass_by_ref_or_value.rs | 2 +- tests/rustdoc-json/attrs/inline.rs | 6 +++--- 6 files changed, 12 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 1688d378feec1..9cab34bfa107d 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -183,21 +183,15 @@ pub enum AttributeKind { ConstStabilityIndirect, /// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute). - Deprecation { - deprecation: Deprecation, - span: Span, - }, + Deprecation { deprecation: Deprecation, span: Span }, /// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html). - DocComment { - style: AttrStyle, - kind: CommentKind, - span: Span, - comment: Symbol, - }, + DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol }, - /// Represents `#[rustc_macro_transparency]`. + /// Represents `#[inline]`. Inline(InlineAttr, Span), + + /// Represents `#[rustc_macro_transparency]`. MacroTransparency(Transparency), /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). diff --git a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs index 141ba7b0636a5..58e51128a0dcb 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs @@ -1,6 +1,6 @@ use super::INLINE_ALWAYS; use clippy_utils::diagnostics::span_lint; -use rustc_attr_parsing::{find_attr, AttributeKind, InlineAttr}; +use rustc_attr_data_structures::{find_attr, AttributeKind, InlineAttr}; use rustc_hir::Attribute; use rustc_lint::LateContext; use rustc_span::symbol::Symbol; diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs index 23c427f3c20cd..617c006795be1 100644 --- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs +++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::DiagExt; -use rustc_attr_parsing::{find_attr, AttributeKind}; +use rustc_attr_data_structures::{find_attr, AttributeKind}; use rustc_errors::Applicability; use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index 25579c10cb97c..f835bbb7c5610 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use rustc_attr_parsing::{find_attr, AttributeKind}; +use rustc_attr_data_structures::{find_attr, AttributeKind}; use rustc_hir as hir; use rustc_hir::Attribute; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index dc86143b10e2f..e18bdfb34ac83 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy}; use clippy_utils::{is_self, is_self_ty}; -use rustc_attr_parsing::{find_attr, AttributeKind, InlineAttr}; +use rustc_attr_data_structures::{find_attr, AttributeKind, InlineAttr}; use rustc_data_structures::fx::FxHashSet; use core::ops::ControlFlow; use rustc_abi::ExternAbi; diff --git a/tests/rustdoc-json/attrs/inline.rs b/tests/rustdoc-json/attrs/inline.rs index 74f5f36f03f3b..b9ea6ab1d10cc 100644 --- a/tests/rustdoc-json/attrs/inline.rs +++ b/tests/rustdoc-json/attrs/inline.rs @@ -1,11 +1,11 @@ -//@ is "$.index[?(@.name=='just_inline')].attrs" '["#[inline]"]' +//@ is "$.index[?(@.name=='just_inline')].attrs" '["#[attr = Inline(Hint)]"]' #[inline] pub fn just_inline() {} -//@ is "$.index[?(@.name=='inline_always')].attrs" '["#[inline(always)]"]' +//@ is "$.index[?(@.name=='inline_always')].attrs" '["#[attr = Inline(Always)]"]' #[inline(always)] pub fn inline_always() {} -//@ is "$.index[?(@.name=='inline_never')].attrs" '["#[inline(never)]"]' +//@ is "$.index[?(@.name=='inline_never')].attrs" '["#[attr = Inline(Never)]"]' #[inline(never)] pub fn inline_never() {}