| use std::num::IntErrorKind; |
| |
| use rustc_ast::{self as ast}; |
| use rustc_errors::codes::*; |
| use rustc_errors::{ |
| Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, |
| }; |
| use rustc_feature::AttributeTemplate; |
| use rustc_hir::AttrPath; |
| use rustc_macros::{Diagnostic, Subdiagnostic}; |
| use rustc_span::{Span, Symbol}; |
| use rustc_target::spec::TargetTuple; |
| |
| #[derive(Diagnostic)] |
| #[diag("invalid predicate `{$predicate}`", code = E0537)] |
| pub(crate) struct InvalidPredicate { |
| #[primary_span] |
| pub span: Span, |
| |
| pub predicate: String, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("{$attr_str} attribute cannot have empty value")] |
| pub(crate) struct DocAliasEmpty<'a> { |
| #[primary_span] |
| pub span: Span, |
| pub attr_str: &'a str, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("{$char_} character isn't allowed in {$attr_str}")] |
| pub(crate) struct DocAliasBadChar<'a> { |
| #[primary_span] |
| pub span: Span, |
| pub attr_str: &'a str, |
| pub char_: char, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("{$attr_str} cannot start or end with ' '")] |
| pub(crate) struct DocAliasStartEnd<'a> { |
| #[primary_span] |
| pub span: Span, |
| pub attr_str: &'a str, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`#[{$name})]` is missing a `{$field}` argument")] |
| pub(crate) struct CguFieldsMissing<'a> { |
| #[primary_span] |
| pub span: Span, |
| pub name: &'a AttrPath, |
| pub field: Symbol, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`#![doc({$attr_name} = \"...\")]` isn't allowed as a crate-level attribute")] |
| pub(crate) struct DocAttrNotCrateLevel { |
| #[primary_span] |
| pub span: Span, |
| pub attr_name: Symbol, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("nonexistent keyword `{$keyword}` used in `#[doc(keyword = \"...\")]`")] |
| #[help("only existing keywords are allowed in core/std")] |
| pub(crate) struct DocKeywordNotKeyword { |
| #[primary_span] |
| pub span: Span, |
| pub keyword: Symbol, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = \"...\")]`")] |
| #[help("only existing builtin attributes are allowed in core/std")] |
| pub(crate) struct DocAttributeNotAttribute { |
| #[primary_span] |
| pub span: Span, |
| pub attribute: Symbol, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("missing 'since'", code = E0542)] |
| pub(crate) struct MissingSince { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("missing 'note'", code = E0543)] |
| pub(crate) struct MissingNote { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("multiple stability levels", code = E0544)] |
| pub(crate) struct MultipleStabilityLevels { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`issue` must be a non-zero numeric string or \"none\"", code = E0545)] |
| pub(crate) struct InvalidIssueString { |
| #[primary_span] |
| pub span: Span, |
| |
| #[subdiagnostic] |
| pub cause: Option<InvalidIssueStringCause>, |
| } |
| |
| // The error kinds of `IntErrorKind` are duplicated here in order to allow the messages to be |
| // translatable. |
| #[derive(Subdiagnostic)] |
| pub(crate) enum InvalidIssueStringCause { |
| #[label("`issue` must not be \"0\", use \"none\" instead")] |
| MustNotBeZero { |
| #[primary_span] |
| span: Span, |
| }, |
| |
| #[label("cannot parse integer from empty string")] |
| Empty { |
| #[primary_span] |
| span: Span, |
| }, |
| |
| #[label("invalid digit found in string")] |
| InvalidDigit { |
| #[primary_span] |
| span: Span, |
| }, |
| |
| #[label("number too large to fit in target type")] |
| PosOverflow { |
| #[primary_span] |
| span: Span, |
| }, |
| |
| #[label("number too small to fit in target type")] |
| NegOverflow { |
| #[primary_span] |
| span: Span, |
| }, |
| } |
| |
| impl InvalidIssueStringCause { |
| pub(crate) fn from_int_error_kind(span: Span, kind: &IntErrorKind) -> Option<Self> { |
| match kind { |
| IntErrorKind::Empty => Some(Self::Empty { span }), |
| IntErrorKind::InvalidDigit => Some(Self::InvalidDigit { span }), |
| IntErrorKind::PosOverflow => Some(Self::PosOverflow { span }), |
| IntErrorKind::NegOverflow => Some(Self::NegOverflow { span }), |
| IntErrorKind::Zero => Some(Self::MustNotBeZero { span }), |
| _ => None, |
| } |
| } |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("missing 'feature'", code = E0546)] |
| pub(crate) struct MissingFeature { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("'feature' is not an identifier", code = E0546)] |
| pub(crate) struct NonIdentFeature { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("missing 'issue'", code = E0547)] |
| pub(crate) struct MissingIssue { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| // FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`? |
| // It is more similar to `IncorrectReprFormatGeneric`. |
| #[derive(Diagnostic)] |
| #[diag("incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all", code = E0552)] |
| pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg { |
| #[primary_span] |
| pub span: Span, |
| } |
| #[derive(Diagnostic)] |
| #[diag("incorrect `repr(packed)` attribute format: `packed` expects a literal integer as argument", code = E0552)] |
| pub(crate) struct IncorrectReprFormatPackedExpectInteger { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("invalid representation hint: `{$name}` does not take a parenthesized argument list", code = E0552)] |
| pub(crate) struct InvalidReprHintNoParen { |
| #[primary_span] |
| pub span: Span, |
| |
| pub name: Symbol, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("invalid representation hint: `{$name}` does not take a value", code = E0552)] |
| pub(crate) struct InvalidReprHintNoValue { |
| #[primary_span] |
| pub span: Span, |
| |
| pub name: Symbol, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("invalid `repr(align)` attribute: `align` needs an argument", code = E0589)] |
| pub(crate) struct InvalidReprAlignNeedArg { |
| #[primary_span] |
| #[suggestion( |
| "supply an argument here", |
| code = "align(...)", |
| applicability = "has-placeholders" |
| )] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("invalid `repr({$repr_arg})` attribute: {$error_part}", code = E0589)] |
| pub(crate) struct InvalidReprGeneric<'a> { |
| #[primary_span] |
| pub span: Span, |
| |
| pub repr_arg: String, |
| pub error_part: &'a str, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses", code = E0693)] |
| pub(crate) struct IncorrectReprFormatAlignOneArg { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("incorrect `repr(align)` attribute format: `align` expects a literal integer as argument", code = E0693)] |
| pub(crate) struct IncorrectReprFormatExpectInteger { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("incorrect `repr({$repr_arg})` attribute format", code = E0693)] |
| pub(crate) struct IncorrectReprFormatGeneric { |
| #[primary_span] |
| pub span: Span, |
| |
| pub repr_arg: Symbol, |
| |
| #[subdiagnostic] |
| pub cause: Option<IncorrectReprFormatGenericCause>, |
| } |
| |
| #[derive(Subdiagnostic)] |
| pub(crate) enum IncorrectReprFormatGenericCause { |
| #[suggestion( |
| "use parentheses instead", |
| code = "{name}({value})", |
| applicability = "machine-applicable" |
| )] |
| Int { |
| #[primary_span] |
| span: Span, |
| |
| #[skip_arg] |
| name: Symbol, |
| |
| #[skip_arg] |
| value: u128, |
| }, |
| |
| #[suggestion( |
| "use parentheses instead", |
| code = "{name}({value})", |
| applicability = "machine-applicable" |
| )] |
| Symbol { |
| #[primary_span] |
| span: Span, |
| |
| #[skip_arg] |
| name: Symbol, |
| |
| #[skip_arg] |
| value: Symbol, |
| }, |
| } |
| |
| impl IncorrectReprFormatGenericCause { |
| pub(crate) fn from_lit_kind(span: Span, kind: &ast::LitKind, name: Symbol) -> Option<Self> { |
| match *kind { |
| ast::LitKind::Int(value, ast::LitIntType::Unsuffixed) => { |
| Some(Self::Int { span, name, value: value.get() }) |
| } |
| ast::LitKind::Str(value, _) => Some(Self::Symbol { span, name, value }), |
| _ => None, |
| } |
| } |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute", code = E0717)] |
| pub(crate) struct RustcPromotablePairing { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute", code = E0789)] |
| pub(crate) struct RustcAllowedUnstablePairing { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("suggestions on deprecated items are unstable")] |
| pub(crate) struct DeprecatedItemSuggestion { |
| #[primary_span] |
| pub span: Span, |
| |
| #[help("add `#![feature(deprecated_suggestion)]` to the crate root")] |
| pub is_nightly: bool, |
| |
| #[note("see #94785 for more details")] |
| pub details: (), |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("expected single version literal")] |
| pub(crate) struct ExpectedSingleVersionLiteral { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("expected a version literal")] |
| pub(crate) struct ExpectedVersionLiteral { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`{$name}` expects a list of feature names")] |
| pub(crate) struct ExpectsFeatureList { |
| #[primary_span] |
| pub span: Span, |
| |
| pub name: String, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`{$name}` expects feature names")] |
| pub(crate) struct ExpectsFeatures { |
| #[primary_span] |
| pub span: Span, |
| |
| pub name: String, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("'since' must be a Rust version number, such as \"1.31.0\"")] |
| pub(crate) struct InvalidSince { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`soft` should not have any arguments")] |
| pub(crate) struct SoftNoArgs { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("unknown version literal format, assuming it refers to a future version")] |
| pub(crate) struct UnknownVersionLiteral { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| // FIXME(jdonszelmann) duplicated from `rustc_passes`, remove once `check_attr` is integrated. |
| #[derive(Diagnostic)] |
| #[diag("multiple `{$name}` attributes")] |
| pub(crate) struct UnusedMultiple { |
| #[primary_span] |
| #[suggestion("remove this attribute", code = "", applicability = "machine-applicable")] |
| pub this: Span, |
| #[note("attribute also specified here")] |
| pub other: Span, |
| pub name: Symbol, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`export_name` may not contain null characters", code = E0648)] |
| pub(crate) struct NullOnExport { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`link_section` may not contain null characters", code = E0648)] |
| pub(crate) struct NullOnLinkSection { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`objc::class!` may not contain null characters")] |
| pub(crate) struct NullOnObjcClass { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`objc::selector!` may not contain null characters")] |
| pub(crate) struct NullOnObjcSelector { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`objc::class!` expected a string literal")] |
| pub(crate) struct ObjcClassExpectedStringLiteral { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`objc::selector!` expected a string literal")] |
| pub(crate) struct ObjcSelectorExpectedStringLiteral { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("stability attributes may not be used outside of the standard library", code = E0734)] |
| pub(crate) struct StabilityOutsideStd { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("expected at least one confusable name")] |
| pub(crate) struct EmptyConfusables { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[help("`#[{$name}]` can {$only}be applied to {$applied}")] |
| #[diag("`#[{$name}]` attribute cannot be used on {$target}")] |
| pub(crate) struct InvalidTarget { |
| #[primary_span] |
| #[suggestion( |
| "remove the attribute", |
| code = "", |
| applicability = "machine-applicable", |
| style = "tool-only" |
| )] |
| pub span: Span, |
| pub name: AttrPath, |
| pub target: &'static str, |
| pub applied: DiagArgValue, |
| pub only: &'static str, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("invalid alignment value: {$error_part}", code = E0589)] |
| pub(crate) struct InvalidAlignmentValue { |
| #[primary_span] |
| pub span: Span, |
| pub error_part: &'static str, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("meta item in `repr` must be an identifier", code = E0565)] |
| pub(crate) struct ReprIdent { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("unrecognized representation hint", code = E0552)] |
| #[help( |
| "valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`" |
| )] |
| #[note( |
| "for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>" |
| )] |
| pub(crate) struct UnrecognizedReprHint { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("item annotated with `#[unstable_feature_bound]` should not be stable")] |
| #[help( |
| "if this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`" |
| )] |
| pub(crate) struct UnstableFeatureBoundIncompatibleStability { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("attribute incompatible with `#[unsafe(naked)]`", code = E0736)] |
| pub(crate) struct NakedFunctionIncompatibleAttribute { |
| #[primary_span] |
| #[label("the `{$attr}` attribute is incompatible with `#[unsafe(naked)]`")] |
| pub span: Span, |
| #[label("function marked with `#[unsafe(naked)]` here")] |
| pub naked_span: Span, |
| pub attr: String, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("ordinal value in `link_ordinal` is too large: `{$ordinal}`")] |
| #[note("the value may not exceed `u16::MAX`")] |
| pub(crate) struct LinkOrdinalOutOfRange { |
| #[primary_span] |
| pub span: Span, |
| pub ordinal: u128, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("element count in `rustc_scalable_vector` is too large: `{$n}`")] |
| #[note("the value may not exceed `u16::MAX`")] |
| pub(crate) struct RustcScalableVectorCountOutOfRange { |
| #[primary_span] |
| pub span: Span, |
| pub n: u128, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("attribute requires {$opt} to be enabled")] |
| pub(crate) struct AttributeRequiresOpt { |
| #[primary_span] |
| pub span: Span, |
| pub opt: &'static str, |
| } |
| |
| pub(crate) enum AttributeParseErrorReason<'a> { |
| ExpectedNoArgs, |
| ExpectedStringLiteral { |
| byte_string: Option<Span>, |
| }, |
| ExpectedFilenameLiteral, |
| ExpectedIntegerLiteral, |
| ExpectedIntegerLiteralInRange { |
| lower_bound: isize, |
| upper_bound: isize, |
| }, |
| ExpectedAtLeastOneArgument, |
| ExpectedSingleArgument, |
| ExpectedList, |
| ExpectedListOrNoArgs, |
| ExpectedListWithNumArgsOrMore { |
| args: usize, |
| }, |
| ExpectedNameValueOrNoArgs, |
| ExpectedNonEmptyStringLiteral, |
| UnexpectedLiteral, |
| ExpectedNameValue(Option<Symbol>), |
| DuplicateKey(Symbol), |
| ExpectedSpecificArgument { |
| possibilities: &'a [Symbol], |
| strings: bool, |
| /// Should we tell the user to write a list when they didn't? |
| list: bool, |
| }, |
| ExpectedIdentifier, |
| } |
| |
| /// A description of a thing that can be parsed using an attribute parser. |
| #[derive(Copy, Clone)] |
| pub enum ParsedDescription { |
| /// Used when parsing attributes. |
| Attribute, |
| /// Used when parsing some macros, such as the `cfg!()` macro. |
| Macro, |
| } |
| |
| pub(crate) struct AttributeParseError<'a> { |
| pub(crate) span: Span, |
| pub(crate) attr_span: Span, |
| pub(crate) template: AttributeTemplate, |
| pub(crate) path: AttrPath, |
| pub(crate) description: ParsedDescription, |
| pub(crate) reason: AttributeParseErrorReason<'a>, |
| pub(crate) suggestions: Vec<String>, |
| } |
| |
| impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> { |
| fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { |
| let name = self.path.to_string(); |
| |
| let description = match self.description { |
| ParsedDescription::Attribute => "attribute", |
| ParsedDescription::Macro => "macro", |
| }; |
| |
| let mut diag = Diag::new(dcx, level, format!("malformed `{name}` {description} 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, |
| "consider removing the prefix", |
| "", |
| 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::ExpectedFilenameLiteral => { |
| diag.span_label(self.span, "expected a filename string literal here"); |
| } |
| AttributeParseErrorReason::ExpectedIntegerLiteral => { |
| diag.span_label(self.span, "expected an integer literal here"); |
| } |
| AttributeParseErrorReason::ExpectedIntegerLiteralInRange { |
| lower_bound, |
| upper_bound, |
| } => { |
| diag.span_label( |
| self.span, |
| format!( |
| "expected an integer literal in the range of {lower_bound}..={upper_bound}" |
| ), |
| ); |
| } |
| AttributeParseErrorReason::ExpectedSingleArgument => { |
| diag.span_label(self.span, "expected a single argument here"); |
| diag.code(E0805); |
| } |
| AttributeParseErrorReason::ExpectedAtLeastOneArgument => { |
| diag.span_label(self.span, "expected at least 1 argument here"); |
| } |
| AttributeParseErrorReason::ExpectedList => { |
| diag.span_label(self.span, "expected this to be a list"); |
| } |
| AttributeParseErrorReason::ExpectedListOrNoArgs => { |
| diag.span_label(self.span, "expected a list or no arguments here"); |
| } |
| AttributeParseErrorReason::ExpectedListWithNumArgsOrMore { args } => { |
| diag.span_label(self.span, format!("expected {args} or more items")); |
| } |
| AttributeParseErrorReason::ExpectedNameValueOrNoArgs => { |
| diag.span_label(self.span, "didn't expect a list here"); |
| } |
| AttributeParseErrorReason::ExpectedNonEmptyStringLiteral => { |
| diag.span_label(self.span, "string is not allowed to be empty"); |
| } |
| 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, "didn't expect a literal here"); |
| diag.code(E0565); |
| } |
| AttributeParseErrorReason::ExpectedNoArgs => { |
| diag.span_label(self.span, "didn't expect any arguments here"); |
| diag.code(E0565); |
| } |
| AttributeParseErrorReason::ExpectedNameValue(None) => { |
| // If the span is the entire attribute, the suggestion we add below this match already contains enough information |
| if self.span != self.attr_span { |
| diag.span_label( |
| self.span, |
| format!("expected this to be of the form `... = \"...\"`"), |
| ); |
| } |
| } |
| AttributeParseErrorReason::ExpectedNameValue(Some(name)) => { |
| diag.span_label( |
| self.span, |
| format!("expected this to be of the form `{name} = \"...\"`"), |
| ); |
| } |
| AttributeParseErrorReason::ExpectedSpecificArgument { |
| possibilities, |
| strings, |
| list: false, |
| } => { |
| let quote = if strings { '"' } else { '`' }; |
| match possibilities { |
| &[] => {} |
| &[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}")); |
| } |
| } |
| } |
| AttributeParseErrorReason::ExpectedSpecificArgument { |
| possibilities, |
| strings, |
| list: true, |
| } => { |
| let quote = if strings { '"' } else { '`' }; |
| match possibilities { |
| &[] => {} |
| &[x] => { |
| diag.span_label( |
| self.span, |
| format!( |
| "this {description} is only valid with {quote}{x}{quote} as an argument" |
| ), |
| ); |
| } |
| [first, second] => { |
| diag.span_label(self.span, format!("this {description} is only valid with either {quote}{first}{quote} or {quote}{second}{quote} as an argument")); |
| } |
| [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!("this {description} is only valid with one of the following arguments: {res}")); |
| } |
| } |
| } |
| AttributeParseErrorReason::ExpectedIdentifier => { |
| diag.span_label(self.span, "expected a valid identifier here"); |
| } |
| } |
| |
| if let Some(link) = self.template.docs { |
| diag.note(format!("for more information, visit <{link}>")); |
| } |
| |
| if self.suggestions.len() < 4 { |
| diag.span_suggestions( |
| self.attr_span, |
| if self.suggestions.len() == 1 { |
| "must be of the form".to_string() |
| } else { |
| format!( |
| "try changing it to one of the following valid forms of the {description}" |
| ) |
| }, |
| self.suggestions, |
| Applicability::HasPlaceholders, |
| ); |
| } |
| |
| diag |
| } |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`{$name}` is not an unsafe attribute")] |
| #[note("extraneous unsafe is not allowed in attributes")] |
| pub(crate) struct InvalidAttrUnsafe { |
| #[primary_span] |
| #[label("this is not an unsafe attribute")] |
| pub span: Span, |
| pub name: AttrPath, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("unsafe attribute used without unsafe")] |
| pub(crate) struct UnsafeAttrOutsideUnsafe { |
| #[primary_span] |
| #[label("usage of unsafe attribute")] |
| pub span: Span, |
| #[subdiagnostic] |
| pub suggestion: Option<UnsafeAttrOutsideUnsafeSuggestion>, |
| } |
| |
| #[derive(Subdiagnostic)] |
| #[multipart_suggestion("wrap the attribute in `unsafe(...)`", applicability = "machine-applicable")] |
| pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion { |
| #[suggestion_part(code = "unsafe(")] |
| pub left: Span, |
| #[suggestion_part(code = ")")] |
| pub right: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("wrong meta list delimiters")] |
| pub(crate) struct MetaBadDelim { |
| #[primary_span] |
| pub span: Span, |
| #[subdiagnostic] |
| pub sugg: MetaBadDelimSugg, |
| } |
| |
| #[derive(Subdiagnostic)] |
| #[multipart_suggestion( |
| "the delimiters should be `(` and `)`", |
| applicability = "machine-applicable" |
| )] |
| pub(crate) struct MetaBadDelimSugg { |
| #[suggestion_part(code = "(")] |
| pub open: Span, |
| #[suggestion_part(code = ")")] |
| pub close: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("expected a literal (`1u8`, `1.0f32`, `\"string\"`, etc.) here, found {$descr}")] |
| pub(crate) struct InvalidMetaItem { |
| #[primary_span] |
| pub span: Span, |
| pub descr: String, |
| #[subdiagnostic] |
| pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>, |
| #[subdiagnostic] |
| pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>, |
| #[label("{$descr}s are not allowed here")] |
| pub label: Option<Span>, |
| } |
| |
| #[derive(Subdiagnostic)] |
| #[multipart_suggestion( |
| "surround the identifier with quotation marks to make it into a string literal", |
| applicability = "machine-applicable" |
| )] |
| pub(crate) struct InvalidMetaItemQuoteIdentSugg { |
| #[suggestion_part(code = "\"")] |
| pub before: Span, |
| #[suggestion_part(code = "\"")] |
| pub after: Span, |
| } |
| |
| #[derive(Subdiagnostic)] |
| #[multipart_suggestion( |
| "negative numbers are not literals, try removing the `-` sign", |
| applicability = "machine-applicable" |
| )] |
| pub(crate) struct InvalidMetaItemRemoveNegSugg { |
| #[suggestion_part(code = "")] |
| pub negative_sign: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("suffixed literals are not allowed in attributes")] |
| #[help( |
| "instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)" |
| )] |
| pub(crate) struct SuffixedLiteralInAttribute { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("link name must not be empty", code = E0454)] |
| pub(crate) struct EmptyLinkName { |
| #[primary_span] |
| #[label("empty link name")] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("link kind `framework` is only supported on Apple targets", code = E0455)] |
| pub(crate) struct LinkFrameworkApple { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`wasm_import_module` is incompatible with other arguments in `#[link]` attributes")] |
| pub(crate) struct IncompatibleWasmLink { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`#[link]` attribute requires a `name = \"string\"` argument", code = E0459)] |
| pub(crate) struct LinkRequiresName { |
| #[primary_span] |
| #[label("missing `name` argument")] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("link name must not contain NUL characters if link kind is `raw-dylib`")] |
| pub(crate) struct RawDylibNoNul { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("link kind `raw-dylib` is only supported on Windows targets", code = E0455)] |
| pub(crate) struct RawDylibOnlyWindows { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag( |
| "invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed, export-symbols" |
| )] |
| pub(crate) struct InvalidLinkModifier { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("multiple `{$modifier}` modifiers in a single `modifiers` argument")] |
| pub(crate) struct MultipleModifiers { |
| #[primary_span] |
| pub span: Span, |
| pub modifier: Symbol, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("import name type is only supported on x86")] |
| pub(crate) struct ImportNameTypeX86 { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("linking modifier `bundle` is only compatible with `static` linking kind")] |
| pub(crate) struct BundleNeedsStatic { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("linking modifier `export-symbols` is only compatible with `static` linking kind")] |
| pub(crate) struct ExportSymbolsNeedsStatic { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("linking modifier `whole-archive` is only compatible with `static` linking kind")] |
| pub(crate) struct WholeArchiveNeedsStatic { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag( |
| "linking modifier `as-needed` is only compatible with `dylib`, `framework` and `raw-dylib` linking kinds" |
| )] |
| pub(crate) struct AsNeededCompatibility { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("import name type can only be used with link kind `raw-dylib`")] |
| pub(crate) struct ImportNameTypeRaw { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`limit` must be a non-negative integer")] |
| pub(crate) struct LimitInvalid<'a> { |
| #[primary_span] |
| pub span: Span, |
| #[label("{$error_str}")] |
| pub value_span: Span, |
| pub error_str: &'a str, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("wrong `cfg_attr` delimiters")] |
| pub(crate) struct CfgAttrBadDelim { |
| #[primary_span] |
| pub span: Span, |
| #[subdiagnostic] |
| pub sugg: MetaBadDelimSugg, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag( |
| "doc alias attribute expects a string `#[doc(alias = \"a\")]` or a list of strings `#[doc(alias(\"a\", \"b\"))]`" |
| )] |
| pub(crate) struct DocAliasMalformed { |
| #[primary_span] |
| pub span: Span, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("definition of an unknown lang item: `{$name}`", code = E0522)] |
| pub(crate) struct UnknownLangItem { |
| #[primary_span] |
| #[label("definition of unknown lang item `{$name}`")] |
| pub span: Span, |
| pub name: Symbol, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("target `{$current_target}` does not support `#[instruction_set({$instruction_set}::*)]`")] |
| pub(crate) struct UnsupportedInstructionSet<'a> { |
| #[primary_span] |
| pub span: Span, |
| pub instruction_set: Symbol, |
| pub current_target: &'a TargetTuple, |
| } |