| use std::num::IntErrorKind; | |
| use rustc_errors::codes::*; | |
| use rustc_errors::{ | |
| Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, | |
| }; | |
| use rustc_hir::AttrPath; | |
| use rustc_hir::attrs::{MirDialect, MirPhase}; | |
| use rustc_macros::{Diagnostic, Subdiagnostic}; | |
| use rustc_span::{Span, Symbol}; | |
| use rustc_target::spec::TargetTuple; | |
| use crate::AttributeTemplate; | |
| use crate::context::Suggestion; | |
| #[derive(Diagnostic)] | |
| #[diag("`#[ffi_const]` function cannot be `#[ffi_pure]`", code = E0757)] | |
| pub(crate) struct BothFfiConstAndPure { | |
| #[primary_span] | |
| pub attr_span: Span, | |
| } | |
| #[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( | |
| "`#[target_feature]` cannot be applied to a {$kind -> | |
| [panic_handler] `#[panic_handler]` | |
| *[other] lang item | |
| } function" | |
| )] | |
| pub(crate) struct TargetFeatureOnLangItem { | |
| #[primary_span] | |
| pub attr_span: Span, | |
| pub kind: Symbol, | |
| #[label( | |
| "{$kind -> | |
| [panic_handler] `#[panic_handler]` | |
| *[other] lang item | |
| } function is not allowed to have `#[target_feature]`" | |
| )] | |
| pub item_span: Span, | |
| } | |
| #[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, | |
| } | |
| #[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("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 be empty")] | |
| pub(crate) struct EmptyExportName { | |
| #[primary_span] | |
| pub span: Span, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("`section` may not be empty")] | |
| pub(crate) struct EmptySection { | |
| #[primary_span] | |
| pub span: Span, | |
| } | |
| #[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("link name may not contain null characters", code = E0648)] | |
| pub(crate) struct NullOnLinkName { | |
| #[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("`section` may not contain null characters", code = E0648)] | |
| pub(crate) struct NullOnSection { | |
| #[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("expected at least one confusable name")] | |
| pub(crate) struct EmptyConfusables { | |
| #[primary_span] | |
| pub span: Span, | |
| } | |
| #[derive(Diagnostic)] | |
| #[help("`#[{$name}{$attribute_args}]` can {$only}be applied to {$applied}")] | |
| #[diag("`#[{$name}{$attribute_args}]` 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, | |
| pub attribute_args: String, | |
| #[subdiagnostic] | |
| pub help: Option<InvalidTargetHelp>, | |
| #[warning( | |
| "this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!" | |
| )] | |
| pub previously_accepted: bool, | |
| #[note( | |
| "placing this attribute on a macro invocation does nothing even if the macro expands to what would be a valid target for the attribute" | |
| )] | |
| pub on_macro_call: bool, | |
| } | |
| #[derive(Subdiagnostic)] | |
| pub(crate) enum InvalidTargetHelp { | |
| #[help("use `#[rustc_align(...)]` instead")] | |
| UseRustcAlign, | |
| #[help("use `#[rustc_align_static(...)]` instead")] | |
| UseRustcAlignStatic, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("invalid alignment value: {$error_part}", code = E0589)] | |
| pub(crate) struct InvalidAlignmentValue { | |
| #[primary_span] | |
| pub span: Span, | |
| pub error_part: String, | |
| } | |
| #[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, | |
| ExpectedArgument, | |
| ExpectedSingleArgument, | |
| ExpectedList, | |
| ExpectedListOrNoArgs, | |
| ExpectedListWithNumArgsOrMore { | |
| args: usize, | |
| }, | |
| ExpectedNameValueOrNoArgs, | |
| ExpectedNonEmptyStringLiteral, | |
| ExpectedNotLiteral, | |
| ExpectedNameValue(Option<Symbol>), | |
| MissingNameValue(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: AttributeParseErrorSuggestions, | |
| } | |
| pub(crate) enum AttributeParseErrorSuggestions { | |
| CreatedByTemplate(Vec<String>), | |
| CreatedByParser(Vec<Suggestion>), | |
| } | |
| impl<'a> AttributeParseError<'a> { | |
| fn render_expected_specific_argument<G>( | |
| &self, | |
| diag: &mut Diag<'_, G>, | |
| possibilities: &[Symbol], | |
| strings: bool, | |
| ) where | |
| G: EmissionGuarantee, | |
| { | |
| 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}")); | |
| } | |
| } | |
| } | |
| fn render_expected_specific_argument_list<G>( | |
| &self, | |
| diag: &mut Diag<'_, G>, | |
| possibilities: &[Symbol], | |
| strings: bool, | |
| ) where | |
| G: EmissionGuarantee, | |
| { | |
| let description = self.description(); | |
| 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}")); | |
| } | |
| } | |
| } | |
| fn render_suggestions<G>(&self, diag: &mut Diag<'_, G>) | |
| where | |
| G: EmissionGuarantee, | |
| { | |
| let description = self.description(); | |
| match &self.suggestions { | |
| AttributeParseErrorSuggestions::CreatedByTemplate(suggestions) => { | |
| diag.span_suggestions( | |
| self.attr_span, | |
| if 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}" | |
| ) | |
| }, | |
| suggestions.iter().cloned(), | |
| Applicability::HasPlaceholders, | |
| ); | |
| } | |
| AttributeParseErrorSuggestions::CreatedByParser(suggestions) => { | |
| for Suggestion { msg, sp, code } in suggestions { | |
| diag.span_suggestion_verbose( | |
| *sp, | |
| msg.to_string(), | |
| code.to_string(), | |
| Applicability::MaybeIncorrect, | |
| ); | |
| } | |
| } | |
| } | |
| } | |
| fn description(&self) -> &'static str { | |
| match self.description { | |
| ParsedDescription::Attribute => "attribute", | |
| ParsedDescription::Macro => "macro", | |
| } | |
| } | |
| } | |
| impl AttributeParseErrorSuggestions { | |
| fn len(&self) -> usize { | |
| match self { | |
| AttributeParseErrorSuggestions::CreatedByTemplate(items) => items.len(), | |
| AttributeParseErrorSuggestions::CreatedByParser(items) => items.len(), | |
| } | |
| } | |
| } | |
| 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 = self.description(); | |
| 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"); | |
| // Avoid emitting an "attribute must be of the form" suggestion, as the | |
| // attribute is likely to be well-formed already. | |
| 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::ExpectedArgument => { | |
| diag.span_label(self.span, "expected an 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::ExpectedNotLiteral => { | |
| 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::MissingNameValue(name) => { | |
| diag.span_label(self.span, format!("missing argument `{name} = \"...\"`")); | |
| } | |
| AttributeParseErrorReason::ExpectedSpecificArgument { | |
| possibilities, | |
| strings, | |
| list: false, | |
| } => { | |
| self.render_expected_specific_argument(&mut diag, *possibilities, *strings); | |
| } | |
| AttributeParseErrorReason::ExpectedSpecificArgument { | |
| possibilities, | |
| strings, | |
| list: true, | |
| } => { | |
| self.render_expected_specific_argument_list(&mut diag, *possibilities, *strings); | |
| } | |
| AttributeParseErrorReason::ExpectedIdentifier => { | |
| diag.span_label(self.span, "expected a valid identifier here"); | |
| diag.code(E0565); | |
| } | |
| } | |
| if let Some(link) = self.template.docs { | |
| diag.note(format!("for more information, visit <{link}>")); | |
| } | |
| if self.suggestions.len() < 4 { | |
| self.render_suggestions(&mut diag); | |
| } | |
| 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 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, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("`dialect` key required")] | |
| pub(crate) struct CustomMirPhaseRequiresDialect { | |
| #[primary_span] | |
| pub attr_span: Span, | |
| #[label("`phase` argument requires a `dialect` argument")] | |
| pub phase_span: Span, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("the {$dialect} dialect is not compatible with the {$phase} phase")] | |
| pub(crate) struct CustomMirIncompatibleDialectAndPhase { | |
| pub dialect: MirDialect, | |
| pub phase: MirPhase, | |
| #[primary_span] | |
| pub attr_span: Span, | |
| #[label("this dialect...")] | |
| pub dialect_span: Span, | |
| #[label("... is not compatible with this phase")] | |
| pub phase_span: Span, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("can't mark as unstable using an already stable feature")] | |
| pub(crate) struct UnstableAttrForAlreadyStableFeature { | |
| #[primary_span] | |
| #[label("this feature is already stable")] | |
| #[help("consider removing the attribute")] | |
| pub attr_span: Span, | |
| #[label("the stability attribute annotates this item")] | |
| pub item_span: Span, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("invalid Mach-O section specifier")] | |
| pub(crate) struct InvalidMachoSection { | |
| #[primary_span] | |
| #[label("not a valid Mach-O section specifier")] | |
| pub name_span: Span, | |
| #[subdiagnostic] | |
| pub reason: InvalidMachoSectionReason, | |
| } | |
| #[derive(Subdiagnostic)] | |
| pub(crate) enum InvalidMachoSectionReason { | |
| #[note("a Mach-O section specifier requires a segment and a section, separated by a comma")] | |
| #[help("an example of a valid Mach-O section specifier is `__TEXT,__cstring`")] | |
| MissingSection, | |
| #[note("section name `{$section}` is longer than 16 bytes")] | |
| SectionTooLong { section: String }, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("`#[sanitize({$field} = ...)]` attribute cannot be used on statics")] | |
| #[help("`#[sanitize]` can be used on statics if only the address is sanitized")] | |
| pub(crate) struct SanitizeInvalidStatic { | |
| #[primary_span] | |
| pub span: Span, | |
| pub field: &'static str, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("attribute items not separated with `,`")] | |
| pub(crate) struct ExpectedComma { | |
| #[primary_span] | |
| #[suggestion( | |
| "try adding `,` here", | |
| code = ",", | |
| applicability = "maybe-incorrect", | |
| style = "short" | |
| )] | |
| pub span: Span, | |
| #[subdiagnostic] | |
| pub additional: Vec<AdditionalCommaSuggestion>, | |
| } | |
| #[derive(Subdiagnostic)] | |
| #[suggestion("try adding `,` here", code = ",", applicability = "maybe-incorrect", style = "short")] | |
| pub(crate) struct AdditionalCommaSuggestion { | |
| #[primary_span] | |
| pub span: Span, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("unused attribute")] | |
| pub(crate) struct UnusedDuplicate { | |
| #[suggestion("remove this attribute", code = "", applicability = "machine-applicable")] | |
| pub this: Span, | |
| #[note("attribute also specified here")] | |
| pub other: Span, | |
| #[warning( | |
| "this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!" | |
| )] | |
| pub warning: bool, | |
| } |