diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 845e4d5e5d0fa..9cab34bfa107d 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, @@ -188,12 +188,14 @@ pub enum AttributeKind { /// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html). DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol }, + /// Represents `#[inline]`. + Inline(InlineAttr, Span), + /// Represents `#[rustc_macro_transparency]`. MacroTransparency(Transparency), /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr(ThinVec<(ReprAttr, Span)>), - /// 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..b9b386635f630 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -23,8 +23,10 @@ attr_parsing_expects_feature_list = attr_parsing_expects_features = `{$name}` expects feature names -attr_parsing_incorrect_meta_item = expected a quoted string literal -attr_parsing_incorrect_meta_item_suggestion = consider surrounding this with quotes +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_repr_format_align_one_arg = incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses @@ -81,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 @@ -122,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 = @@ -136,6 +131,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..c911908dfb381 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,33 @@ 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 { + cx.expected_list(cx.attr_span); + return; }; - this.confusables.push(lit.symbol); - } + 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().and_then(|i| i.value_str()) else { + cx.expected_string_literal(span, param.lit()); + continue; + }; + + this.confusables.push(lit); + } - this.first_span.get_or_insert(cx.attr_span); - })]; + 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..702ad66f57805 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; @@ -6,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; @@ -18,25 +18,18 @@ 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() { 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 { - // FIXME(jdonszelmann): suggestion? - cx.emit_err(session_diagnostics::IncorrectMetaItem { span: param_span, suggestion: None }); + cx.expected_name_value(param_span, Some(name)); None } } @@ -45,6 +38,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(); @@ -55,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.emit_err(session_diagnostics::UnknownMetaItem { - span: param_span, - item: param.path().to_string(), - expected: 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 c7f82082c2eec..25efc3ae49b9d 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.word_without_args().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)) } @@ -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) => { @@ -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/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index caf55e6685efc..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; @@ -29,13 +30,14 @@ 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; 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. /// @@ -87,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; } @@ -103,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 @@ -125,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) @@ -222,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>, @@ -241,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..ae9e7871874d6 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>, @@ -31,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/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 3cbadd4c7ec22..0eec9d2b7380c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -5,7 +5,8 @@ use rustc_attr_data_structures::{ StableSince, UnstableReason, VERSION_PLACEHOLDER, }; use rustc_errors::ErrorGuaranteed; -use rustc_span::{Span, Symbol, sym}; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Ident, Span, Symbol, sym}; use super::util::parse_version; use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser}; @@ -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; }), @@ -199,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() @@ -212,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 } } @@ -241,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, @@ -309,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. @@ -343,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 16ad9d03e500d..ce5ceb9139a5c 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,14 +18,23 @@ 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()) { + 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 47f72232828ee..56defacc84d08 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -5,12 +5,11 @@ 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}; -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}; @@ -18,6 +17,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, RustcForceInlineParser}; use crate::attributes::repr::ReprParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, @@ -25,11 +25,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, UnknownMetaItem}; 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>> )> }; @@ -58,7 +59,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(); $( { @@ -66,13 +67,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| { @@ -104,6 +104,8 @@ attribute_parsers!( // tidy-alphabetical-start Single, Single, + Single, + Single, Single, // tidy-alphabetical-end ]; @@ -163,6 +165,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> { @@ -170,10 +180,133 @@ 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 unknown_key( + &self, + span: Span, + found: String, + options: &'static [&'static str], + ) -> ErrorGuaranteed { + self.emit_err(UnknownMetaItem { span, item: found, expected: options }) + } + + /// 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 { + byte_string: actual_literal.and_then(|i| { + i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span)) + }), + }, + }) + } + + 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), + }) + } + + /// 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, + 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, + 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 { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedSpecificArgument { + possibilities, + strings: true, + }, + }) + } } impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> { @@ -372,18 +505,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..57ac92a0ca190 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}; @@ -12,8 +16,6 @@ pub(crate) enum UnsupportedLiteralReason { Generic, CfgString, CfgBoolean, - DeprecatedString, - DeprecatedKvPair, } #[derive(Diagnostic)] @@ -32,37 +34,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, @@ -217,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, @@ -239,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); @@ -462,6 +428,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 +464,115 @@ pub(crate) struct UnrecognizedReprHint { #[primary_span] pub span: Span, } + +pub(crate) enum AttributeParseErrorReason { + ExpectedStringLiteral { byte_string: Option }, + ExpectedSingleArgument, + ExpectedList, + UnexpectedLiteral, + ExpectedNameValue(Option), + DuplicateKey(Symbol), + ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool }, +} + +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 { 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_label(self.span, "expected a single argument here"); + diag.code(E0805); + } + AttributeParseErrorReason::ExpectedList => { + diag.span_label(self.span, "expected this to be a list"); + } + AttributeParseErrorReason::DuplicateKey(key) => { + 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_label( + self.span, + format!("expected this to be of the form `{name} = \"...\"`"), + ); + } + AttributeParseErrorReason::ExpectedNameValue(Some(name)) => { + diag.span_label( + 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_label( + self.span, + format!("the only valid argument here is {quote}{x}{quote}"), + ); + } + [first, second] => { + 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(); + for i in first { + res.push_str(&format!("{quote}{i}{quote}, ")); + } + res.push_str(&format!( + "{quote}{second_to_last}{quote} or {quote}{last}{quote}" + )); + + diag.span_label(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 { + "try changing it to one of the following valid forms of the attribute" + }, + 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 0b31fa8fa886b..188a9a98ce7a0 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -4,7 +4,9 @@ use rustc_abi::ExternAbi; 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::{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 +23,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}; @@ -83,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(); @@ -449,48 +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 = 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 - } - }); + 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 @@ -511,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_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_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_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..b3096e46b09ca 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -282,11 +282,22 @@ 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 + | sym::rustc_confusables + | sym::repr + | sym::deprecated + ) { + 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 4e2be8ff0b817..af83b80f9374c 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,10 @@ 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) + } Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self .check_allow_internal_unstable( hir_id, @@ -155,7 +159,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 +370,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 +434,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 +450,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::IgnoredInlineAttrFnProto, ) } @@ -451,25 +461,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 +484,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::InlineIgnoredForExported {}, ); } @@ -676,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 _ => {} } @@ -787,7 +804,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 +847,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 +867,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 +921,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 +1636,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 +1678,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 +1712,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 +1734,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 +1908,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 +1933,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 +2280,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 +2658,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 +2673,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 +2906,9 @@ 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(i, span) if !matches!(i, InlineAttr::Force{..}) => *span) + { + tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span }); } } @@ -2908,6 +2928,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..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,29 +1,22 @@ use super::INLINE_ALWAYS; -use super::utils::is_word; use clippy_utils::diagnostics::span_lint; +use rustc_attr_data_structures::{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..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,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::DiagExt; +use rustc_attr_data_structures::{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..f835bbb7c5610 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_data_structures::{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..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,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_data_structures::{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; } } 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() {} 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/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..3ed4efeb4dbc6 100644 --- a/tests/ui/attributes/rustc_confusables.stderr +++ b/tests/ui/attributes/rustc_confusables.stderr @@ -1,25 +1,26 @@ -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 - | -LL | #[rustc_confusables(invalid_meta_item)] - | ^^^^^^^^^^^^^^^^^ +error[E0539]: malformed `rustc_confusables` attribute input + --> $DIR/rustc_confusables.rs:34:5 | -help: consider surrounding this with quotes +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")] - | + + +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 d5b149b18ed6a..80198ab81968f 100644 --- a/tests/ui/deprecation/deprecation-sanity.rs +++ b/tests/ui/deprecation/deprecation-sanity.rs @@ -4,22 +4,22 @@ 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 + #[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() { } } @@ -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..f1b4697485cfc 100644 --- a/tests/ui/deprecation/deprecation-sanity.stderr +++ b/tests/ui/deprecation/deprecation-sanity.stderr @@ -4,43 +4,115 @@ 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 - --> $DIR/deprecation-sanity.rs:7:31 +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 = "..."` + | +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 - --> $DIR/deprecation-sanity.rs:10:18 +error[E0539]: malformed `deprecated` attribute input + --> $DIR/deprecation-sanity.rs:10:5 | LL | #[deprecated(since, note = "a")] - | ^^^^^ + | ^^^^^^^^^^^^^-----^^^^^^^^^^^^^^ + | | + | expected this to be of the form `since = "..."` + | +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 - --> $DIR/deprecation-sanity.rs:13:31 +error[E0539]: malformed `deprecated` attribute input + --> $DIR/deprecation-sanity.rs:13:5 | LL | #[deprecated(since = "a", note(b))] - | ^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^ + | | + | expected this to be of the form `note = "..."` + | +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 - --> $DIR/deprecation-sanity.rs:16:18 +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 = "..."` + | +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 +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 @@ -54,11 +126,25 @@ note: attribute also specified here LL | #[deprecated(since = "a", note = "b")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0538]: multiple 'since' items - --> $DIR/deprecation-sanity.rs:30:27 +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 + | +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/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.rs b/tests/ui/error-codes/E0534.rs deleted file mode 100644 index a424249941979..0000000000000 --- a/tests/ui/error-codes/E0534.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[inline()] //~ ERROR E0534 -pub fn something() {} - -fn main() { - something(); -} diff --git a/tests/ui/error-codes/E0534.stderr b/tests/ui/error-codes/E0534.stderr deleted file mode 100644 index 6983de7ab69c6..0000000000000 --- a/tests/ui/error-codes/E0534.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0534]: expected one argument - --> $DIR/E0534.rs:1:1 - | -LL | #[inline()] - | ^^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0534`. 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/E0540.rs b/tests/ui/error-codes/E0540.rs new file mode 100644 index 0000000000000..db29e6801f582 --- /dev/null +++ b/tests/ui/error-codes/E0540.rs @@ -0,0 +1,6 @@ +#[inline()] //~ ERROR malformed `inline` attribute input +pub fn something() {} + +fn main() { + something(); +} 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 bdca6163473c6..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]` and `#[inline(always|never)]` - --> $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.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..3b3da00ae88c7 100644 --- a/tests/ui/force-inlining/invalid.stderr +++ b/tests/ui/force-inlining/invalid.stderr @@ -1,71 +1,71 @@ -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[E0805]: malformed `rustc_force_inline` attribute input + --> $DIR/invalid.rs:15:1 | LL | #[rustc_force_inline(bar, baz)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^----------^ + | | + | expected a single argument here | -help: the following are the 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"] | 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)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^-^^ + | | + | expected a string literal here | -help: the following are the 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"] | 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] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^-^ + | | + | expected a string literal here | -help: the following are the 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"] | 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 +74,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 +83,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 +92,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 +101,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 +110,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 +125,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 +134,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 +147,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 +162,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 +175,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 +184,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 +196,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 +211,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 +220,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 +233,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 +245,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 +254,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 +262,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 +271,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 +280,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 +289,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 +310,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 +319,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 +328,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 +337,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 +346,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 +355,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 +364,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 +373,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 +381,7 @@ LL | LL | fn foo(); | --------- not a function definition -error: aborting due to 38 previous errors +error: aborting due to 37 previous errors +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.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..54e6b2b540824 100644 --- a/tests/ui/invalid/invalid-inline.stderr +++ b/tests/ui/invalid/invalid-inline.stderr @@ -1,15 +1,36 @@ -error[E0534]: expected one argument +error[E0805]: malformed `inline` attribute input --> $DIR/invalid-inline.rs:3:1 | LL | #[inline(please,no)] - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^-----------^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[inline(please,no)] +LL + #[inline(always|never)] + | +LL - #[inline(please,no)] +LL + #[inline] + | -error[E0534]: expected one argument +error[E0805]: malformed `inline` attribute input --> $DIR/invalid-inline.rs:7: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 2 previous errors -For more information about this error, try `rustc --explain E0534`. +For more information about this error, try `rustc --explain E0805`. 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..bd4eb8bbed373 100644 --- a/tests/ui/issues/issue-43988.stderr +++ b/tests/ui/issues/issue-43988.stderr @@ -1,14 +1,19 @@ -error: malformed `repr` attribute input - --> $DIR/issue-43988.rs:24:5 +error[E0539]: malformed `inline` attribute input + --> $DIR/issue-43988.rs:10:5 | -LL | #[repr] - | ^^^^^^^ help: must be of the form: `#[repr(C)]` - -error: malformed `repr` attribute input - --> $DIR/issue-43988.rs:34:14 +LL | #[inline(XYZ)] + | ^^^^^^^^^---^^ + | | + | valid arguments are `always` or `never` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[inline(XYZ)] +LL + #[inline(always|never)] + | +LL - #[inline(XYZ)] +LL + #[inline] | -LL | let _z = #[repr] 1; - | ^^^^^^^ help: must be of the form: `#[repr(C)]` error[E0552]: unrecognized representation hint --> $DIR/issue-43988.rs:14:12 @@ -26,6 +31,41 @@ 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)] + | ^^^^^^^^^---^^ + | | + | valid arguments are `always` or `never` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[inline(ABC)] +LL + #[inline(always|never)] + | +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 | @@ -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..e1c45e832af3f 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -102,19 +102,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 | @@ -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 6b41eb530dbc8..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() {} } } -#[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/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/E0535.rs deleted file mode 100644 index e26334e9bbdc6..0000000000000 --- a/tests/ui/span/E0535.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[inline(unknown)] //~ ERROR E0535 -pub fn something() {} - -fn main() { - something(); -} diff --git a/tests/ui/span/E0535.stderr b/tests/ui/span/E0535.stderr deleted file mode 100644 index 9060b687f508c..0000000000000 --- a/tests/ui/span/E0535.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0535]: invalid argument - --> $DIR/E0535.rs:1:10 - | -LL | #[inline(unknown)] - | ^^^^^^^ - | - = 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`. diff --git a/tests/ui/span/E0539.rs b/tests/ui/span/E0539.rs new file mode 100644 index 0000000000000..e0c6dbfc591f6 --- /dev/null +++ b/tests/ui/span/E0539.rs @@ -0,0 +1,6 @@ +#[inline(unknown)] //~ ERROR malformed `inline` attribute +pub fn something() {} + +fn main() { + something(); +} diff --git a/tests/ui/span/E0539.stderr b/tests/ui/span/E0539.stderr new file mode 100644 index 0000000000000..01f091a26764f --- /dev/null +++ b/tests/ui/span/E0539.stderr @@ -0,0 +1,20 @@ +error[E0539]: malformed `inline` attribute input + --> $DIR/E0539.rs:1:1 + | +LL | #[inline(unknown)] + | ^^^^^^^^^-------^^ + | | + | valid arguments are `always` or `never` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[inline(unknown)] +LL + #[inline(always|never)] + | +LL - #[inline(unknown)] +LL + #[inline] + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0539`. 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..5b35a51cad729 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr @@ -1,8 +1,11 @@ -error[E0538]: multiple 'feature' items - --> $DIR/stability-attribute-sanity-2.rs:7:25 +error[E0538]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity-2.rs:7:1 | 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.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..ae948237d7edf 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity.stderr @@ -4,29 +4,41 @@ 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 - --> $DIR/stability-attribute-sanity.rs:11:29 +error[E0539]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity.rs:11:5 | 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]: expected a quoted string literal - --> $DIR/stability-attribute-sanity.rs:14:14 +error[E0539]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity.rs:14:5 | 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]: expected a quoted string literal - --> $DIR/stability-attribute-sanity.rs:17:29 +error[E0539]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity.rs:17:5 | 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]: expected a quoted string literal - --> $DIR/stability-attribute-sanity.rs:20:14 +error[E0539]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity.rs:20:5 | 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