Auto merge of #138165 - jdonszelmann:inline, r=oli-obk
Rewrite `inline` attribute parser to use new infrastructure and improve diagnostics for all parsed attributes r? `@oli-obk` This PR: - creates a new parser for inline attributes - creates consistent error messages and error codes between attribute parsers; inline and others - as such changes a few error messages for other attributes to be (in my eyes) much more consistent - tests ast-lowering lints introduced by rust-lang/rust#138164 since this is now useful for the first time - Coalesce some useless error codes Builds on top of rust-lang/rust#138164 Closes rust-lang/rust#137950
This commit is contained in:
commit
1bb335244c
66 changed files with 1221 additions and 679 deletions
|
|
@ -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,
|
||||
|
|
@ -221,6 +221,9 @@ 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]` and `#[rustc_force_inline]`.
|
||||
Inline(InlineAttr, Span),
|
||||
|
||||
/// Represents `#[rustc_macro_transparency]`.
|
||||
MacroTransparency(Transparency),
|
||||
|
||||
|
|
|
|||
|
|
@ -11,4 +11,5 @@ pub struct AttributeLint<Id> {
|
|||
#[derive(Clone, Debug, HashStable_Generic)]
|
||||
pub enum AttributeLintKind {
|
||||
UnusedDuplicate { this: Span, other: Span, warning: bool },
|
||||
IllFormedAttributeInput { suggestions: Vec<String> },
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
|
|||
const PATH: &[Symbol] = &[sym::allow_internal_unstable];
|
||||
type Item = (Symbol, Span);
|
||||
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
|
||||
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
|
|
@ -29,6 +31,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
|
|||
const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
|
||||
type Item = Symbol;
|
||||
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowConstFnUnstable;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
|
||||
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
|
|
|
|||
|
|
@ -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<S: Stage> AttributeParser<S> for ConfusablesParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(&[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<Self, S> = &[(
|
||||
&[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 });
|
||||
}
|
||||
|
||||
this.first_span.get_or_insert(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);
|
||||
},
|
||||
)];
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if self.confusables.is_empty() {
|
||||
|
|
|
|||
|
|
@ -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<S: Stage>(
|
|||
item: &Option<Symbol>,
|
||||
) -> Option<Symbol> {
|
||||
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<S: Stage> SingleAttributeParser<S> for DeprecationParser {
|
|||
const PATH: &[Symbol] = &[sym::deprecated];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = 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<AttributeKind> {
|
||||
let features = cx.features();
|
||||
|
|
@ -55,57 +53,60 @@ impl<S: Stage> SingleAttributeParser<S> 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;
|
||||
};
|
||||
|
||||
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: (),
|
||||
});
|
||||
}
|
||||
|
||||
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"]
|
||||
},
|
||||
});
|
||||
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();
|
||||
|
||||
match ident_name {
|
||||
Some(name @ sym::since) => {
|
||||
since = Some(get(cx, name, param.span(), param.args(), &since)?);
|
||||
}
|
||||
Some(name @ sym::note) => {
|
||||
note = Some(get(cx, name, param.span(), param.args(), ¬e)?);
|
||||
}
|
||||
Some(name @ sym::suggestion) => {
|
||||
if !features.deprecated_suggestion() {
|
||||
cx.emit_err(session_diagnostics::DeprecatedItemSuggestion {
|
||||
span: param.span(),
|
||||
is_nightly: cx.sess().is_nightly_build(),
|
||||
details: (),
|
||||
});
|
||||
}
|
||||
|
||||
suggestion =
|
||||
Some(get(cx, name, param.span(), param.args(), &suggestion)?);
|
||||
}
|
||||
_ => {
|
||||
cx.unknown_key(
|
||||
param.span(),
|
||||
param.path().to_string(),
|
||||
if features.deprecated_suggestion() {
|
||||
&["since", "note", "suggestion"]
|
||||
} else {
|
||||
&["since", "note"]
|
||||
},
|
||||
);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ impl<S: Stage> SingleAttributeParser<S> 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<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
|
|||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: "reason", NameValueStr: "reason");
|
||||
|
||||
fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let reason = match args {
|
||||
ArgParser::NoArgs => None,
|
||||
ArgParser::List(list) => {
|
||||
|
|
@ -73,7 +73,7 @@ impl<S: Stage> SingleAttributeParser<S> 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<S: Stage> SingleAttributeParser<S> 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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||
|
|
@ -9,10 +10,9 @@ pub(crate) struct AsPtrParser;
|
|||
|
||||
impl<S: Stage> SingleAttributeParser<S> for AsPtrParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_as_ptr];
|
||||
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
|
||||
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
// FIXME: check that there's no args (this is currently checked elsewhere)
|
||||
|
|
|
|||
|
|
@ -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,6 +30,7 @@ pub(crate) mod allow_unstable;
|
|||
pub(crate) mod cfg;
|
||||
pub(crate) mod confusables;
|
||||
pub(crate) mod deprecation;
|
||||
pub(crate) mod inline;
|
||||
pub(crate) mod lint_helpers;
|
||||
pub(crate) mod repr;
|
||||
pub(crate) mod stability;
|
||||
|
|
@ -36,7 +38,7 @@ pub(crate) mod transparency;
|
|||
pub(crate) mod util;
|
||||
|
||||
type AcceptFn<T, S> = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>);
|
||||
type AcceptMapping<T, S> = &'static [(&'static [Symbol], AcceptFn<T, S>)];
|
||||
type AcceptMapping<T, S> = &'static [(&'static [Symbol], AttributeTemplate, AcceptFn<T, S>)];
|
||||
|
||||
/// An [`AttributeParser`] is a type which searches for syntactic attributes.
|
||||
///
|
||||
|
|
@ -88,6 +90,9 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
|
|||
const ATTRIBUTE_ORDER: AttributeOrder;
|
||||
const ON_DUPLICATE: OnDuplicate<S>;
|
||||
|
||||
/// 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<AttributeKind>;
|
||||
}
|
||||
|
|
@ -104,8 +109,10 @@ impl<T: SingleAttributeParser<S>, S: Stage> Default for Single<T, S> {
|
|||
}
|
||||
|
||||
impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S> {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> =
|
||||
&[(T::PATH, |group: &mut Single<T, S>, cx, args| {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
|
||||
T::PATH,
|
||||
<T as SingleAttributeParser<S>>::TEMPLATE,
|
||||
|group: &mut Single<T, S>, cx, args| {
|
||||
if let Some(pa) = T::convert(cx, args) {
|
||||
match T::ATTRIBUTE_ORDER {
|
||||
// keep the first and report immediately. ignore this attribute
|
||||
|
|
@ -126,7 +133,8 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S>
|
|||
|
||||
group.1 = Some((pa, cx.attr_span));
|
||||
}
|
||||
})];
|
||||
},
|
||||
)];
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
Some(self.1?.0)
|
||||
|
|
@ -223,6 +231,9 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
|
|||
type Item;
|
||||
const CONVERT: ConvertFn<Self::Item>;
|
||||
|
||||
/// The template this attribute parser should implement. Used for diagnostics.
|
||||
const TEMPLATE: AttributeTemplate;
|
||||
|
||||
/// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`]
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
|
|
@ -242,8 +253,11 @@ impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> {
|
|||
}
|
||||
|
||||
impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S> {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> =
|
||||
&[(T::PATH, |group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)))];
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
|
||||
T::PATH,
|
||||
<T as CombineAttributeParser<S>>::TEMPLATE,
|
||||
|group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)),
|
||||
)];
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) }
|
||||
|
|
|
|||
|
|
@ -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<S: Stage> CombineAttributeParser<S> for ReprParser {
|
|||
type Item = (ReprAttr, Span);
|
||||
const PATH: &[Symbol] = &[sym::repr];
|
||||
const CONVERT: ConvertFn<Self::Item> = 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<S: Stage> CombineAttributeParser<S> for ReprParser {
|
|||
let mut reprs = Vec::new();
|
||||
|
||||
let Some(list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
return reprs;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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<S: Stage> AttributeParser<S> for StabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[
|
||||
(&[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<AttributeKind> {
|
||||
|
|
@ -96,8 +110,10 @@ pub(crate) struct BodyStabilityParser {
|
|||
}
|
||||
|
||||
impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> =
|
||||
&[(&[sym::rustc_default_body_unstable], |this, cx, args| {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
|
||||
&[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<S: Stage> AttributeParser<S> 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<AttributeKind> {
|
||||
let (stability, span) = self.stability?;
|
||||
|
|
@ -120,6 +137,7 @@ impl<S: Stage> SingleAttributeParser<S> for ConstStabilityIndirectParser {
|
|||
const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
|
||||
fn convert(_cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
Some(AttributeKind::ConstStabilityIndirect)
|
||||
|
|
@ -146,7 +164,7 @@ impl ConstStabilityParser {
|
|||
|
||||
impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[
|
||||
(&[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<S: Stage> AttributeParser<S> 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<S: Stage> AttributeParser<S> 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<S: Stage>(
|
|||
cx: &AcceptContext<'_, '_, S>,
|
||||
param: &MetaItemParser<'_>,
|
||||
item: &mut Option<Symbol>,
|
||||
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<S: Stage>(
|
|||
*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<S: Stage>(
|
|||
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,
|
||||
|
|
@ -310,11 +328,16 @@ pub(crate) fn parse_unstability<S: Stage>(
|
|||
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.
|
||||
|
|
@ -344,9 +367,11 @@ pub(crate) fn parse_unstability<S: Stage>(
|
|||
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())?
|
||||
}
|
||||
Some(sym::old_name) => {
|
||||
insert_value_into_option_or_error(cx, ¶m, &mut old_name, word.unwrap())?
|
||||
}
|
||||
Some(sym::old_name) => insert_value_into_option_or_error(cx, ¶m, &mut old_name)?,
|
||||
_ => {
|
||||
cx.emit_err(session_diagnostics::UnknownMetaItem {
|
||||
span: param.span(),
|
||||
|
|
|
|||
|
|
@ -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<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
|||
const ON_DUPLICATE: OnDuplicate<S> = 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<AttributeKind> {
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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::lint_helpers::AsPtrParser;
|
||||
use crate::attributes::repr::ReprParser;
|
||||
use crate::attributes::stability::{
|
||||
|
|
@ -26,11 +26,12 @@ use crate::attributes::stability::{
|
|||
use crate::attributes::transparency::TransparencyParser;
|
||||
use crate::attributes::{AttributeParser as _, Combine, Single};
|
||||
use crate::parser::{ArgParser, MetaItemParser};
|
||||
use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
|
||||
|
||||
macro_rules! group_type {
|
||||
($stage: ty) => {
|
||||
LazyLock<(
|
||||
BTreeMap<&'static [Symbol], Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>>,
|
||||
BTreeMap<&'static [Symbol], Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>)>>,
|
||||
Vec<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $stage>) -> Option<AttributeKind>>>
|
||||
)>
|
||||
};
|
||||
|
|
@ -59,7 +60,7 @@ macro_rules! attribute_parsers {
|
|||
@[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
|
||||
) => {
|
||||
pub(crate) static $name: group_type!($ty) = LazyLock::new(|| {
|
||||
let mut accepts = BTreeMap::<_, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>>::new();
|
||||
let mut accepts = BTreeMap::<_, Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>)>>::new();
|
||||
let mut finalizes = Vec::<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $ty>) -> Option<AttributeKind>>>::new();
|
||||
$(
|
||||
{
|
||||
|
|
@ -67,13 +68,12 @@ macro_rules! attribute_parsers {
|
|||
static STATE_OBJECT: RefCell<$names> = RefCell::new(<$names>::default());
|
||||
};
|
||||
|
||||
for (k, v) in <$names>::ATTRIBUTES {
|
||||
let old = accepts.insert(*k, Box::new(|cx, args| {
|
||||
for (path, template, accept_fn) in <$names>::ATTRIBUTES {
|
||||
accepts.entry(*path).or_default().push((*template, Box::new(|cx, args| {
|
||||
STATE_OBJECT.with_borrow_mut(|s| {
|
||||
v(s, cx, args)
|
||||
accept_fn(s, cx, args)
|
||||
})
|
||||
}));
|
||||
assert!(old.is_none());
|
||||
})));
|
||||
}
|
||||
|
||||
finalizes.push(Box::new(|cx| {
|
||||
|
|
@ -106,6 +106,8 @@ attribute_parsers!(
|
|||
Single<AsPtrParser>,
|
||||
Single<ConstStabilityIndirectParser>,
|
||||
Single<DeprecationParser>,
|
||||
Single<InlineParser>,
|
||||
Single<RustcForceInlineParser>,
|
||||
Single<TransparencyParser>,
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
|
@ -165,6 +167,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> {
|
||||
|
|
@ -172,10 +182,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<Symbol>) -> 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> {
|
||||
|
|
@ -374,18 +507,22 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
let args = parser.args();
|
||||
let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
|
||||
|
||||
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),
|
||||
};
|
||||
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)
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -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<L: LintEmitter>(lint: &AttributeLint<HirId>, 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(),
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<IncorrectMetaItemSuggestion>,
|
||||
}
|
||||
|
||||
#[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<Span> },
|
||||
ExpectedSingleArgument,
|
||||
ExpectedList,
|
||||
UnexpectedLiteral,
|
||||
ExpectedNameValue(Option<Symbol>),
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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 {}
|
||||
|
|
|
|||
26
compiler/rustc_error_codes/src/error_codes/E0805.md
Normal file
26
compiler/rustc_error_codes/src/error_codes/E0805.md
Normal file
|
|
@ -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() {}
|
||||
```
|
||||
|
|
@ -547,6 +547,7 @@ E0801: 0801,
|
|||
E0802: 0802,
|
||||
E0803: 0803,
|
||||
E0804: 0804,
|
||||
E0805: 0805,
|
||||
);
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<String> {
|
||||
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
|
||||
} };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2626,6 +2626,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 {
|
||||
|
|
|
|||
|
|
@ -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![];
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -158,7 +162,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,
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
|
|||
// will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line
|
||||
// are deliberately not in a doc comment, because they need not be in public docs.)
|
||||
//
|
||||
// Latest feature: rustdoc JSON: Don't apply #[repr] privacy heuristics
|
||||
pub const FORMAT_VERSION: u32 = 46;
|
||||
// Latest feature: Pretty printing of inline attributes changed
|
||||
pub const FORMAT_VERSION: u32 = 48;
|
||||
|
||||
/// The root of the emitted JSON blob.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
error[E0539]: malformed `rustc_confusables` attribute input
|
||||
--> $DIR/rustc_confusables.rs:34:5
|
||||
|
|
||||
LL | #[rustc_confusables]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| expected this to be a list
|
||||
| help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]`
|
||||
|
||||
error[E0539]: malformed `rustc_confusables` attribute input
|
||||
--> $DIR/rustc_confusables.rs:39:5
|
||||
|
|
||||
LL | #[rustc_confusables(invalid_meta_item)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider surrounding this with quotes
|
||||
|
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
#[inline()] //~ ERROR E0534
|
||||
pub fn something() {}
|
||||
|
||||
fn main() {
|
||||
something();
|
||||
}
|
||||
|
|
@ -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`.
|
||||
|
|
@ -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() { }
|
||||
13
tests/ui/error-codes/E0539.stderr
Normal file
13
tests/ui/error-codes/E0539.stderr
Normal file
|
|
@ -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`.
|
||||
6
tests/ui/error-codes/E0540.rs
Normal file
6
tests/ui/error-codes/E0540.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#[inline()] //~ ERROR malformed `inline` attribute input
|
||||
pub fn something() {}
|
||||
|
||||
fn main() {
|
||||
something();
|
||||
}
|
||||
19
tests/ui/error-codes/E0540.stderr
Normal file
19
tests/ui/error-codes/E0540.stderr
Normal file
|
|
@ -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`.
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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.
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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: malformed `rustc_force_inline` attribute input
|
||||
--> $DIR/invalid.rs:16:1
|
||||
|
|
||||
LL | #[rustc_force_inline(bar, baz)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: the following are the possible correct uses
|
||||
|
|
||||
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
|
||||
|
|
||||
LL | #[rustc_force_inline(2)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: the following are the possible correct uses
|
||||
|
|
||||
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
|
||||
|
|
||||
LL | #[rustc_force_inline = 2]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: the following are the possible correct uses
|
||||
|
|
||||
LL - #[rustc_force_inline = 2]
|
||||
LL + #[rustc_force_inline = "reason"]
|
||||
|
|
||||
LL - #[rustc_force_inline = 2]
|
||||
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:133:11
|
||||
--> $DIR/invalid.rs:132:11
|
||||
|
|
||||
LL | fn barqux(#[rustc_force_inline] _x: u32) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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: 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[E0539]: malformed `rustc_force_inline` attribute input
|
||||
--> $DIR/invalid.rs:20:1
|
||||
|
|
||||
LL | #[rustc_force_inline(2)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^-^^
|
||||
| |
|
||||
| expected a string literal here
|
||||
|
|
||||
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[E0539]: malformed `rustc_force_inline` attribute input
|
||||
--> $DIR/invalid.rs:25:1
|
||||
|
|
||||
LL | #[rustc_force_inline = 2]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^-^
|
||||
| |
|
||||
| expected a string literal here
|
||||
|
|
||||
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: 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<T>),
|
|||
| -------------------------------- 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`.
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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() { }
|
||||
|
|
|
|||
|
|
@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/57571>
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
#[inline(unknown)] //~ ERROR E0535
|
||||
pub fn something() {}
|
||||
|
||||
fn main() {
|
||||
something();
|
||||
}
|
||||
|
|
@ -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`.
|
||||
6
tests/ui/span/E0539.rs
Normal file
6
tests/ui/span/E0539.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#[inline(unknown)] //~ ERROR malformed `inline` attribute
|
||||
pub fn something() {}
|
||||
|
||||
fn main() {
|
||||
something();
|
||||
}
|
||||
20
tests/ui/span/E0539.stderr
Normal file
20
tests/ui/span/E0539.stderr
Normal file
|
|
@ -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`.
|
||||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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() { }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue