rustc_attr_parsing/
session_diagnostics.rs

1use std::num::IntErrorKind;
2
3use rustc_ast::{self as ast, AttrStyle, Path};
4use rustc_errors::codes::*;
5use rustc_errors::{
6    Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
7};
8use rustc_feature::AttributeTemplate;
9use rustc_hir::{AttrPath, Target};
10use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
11use rustc_span::{Span, Symbol};
12
13use crate::fluent_generated as fluent;
14
15pub(crate) enum UnsupportedLiteralReason {
16    Generic,
17    CfgString,
18    CfgBoolean,
19}
20
21#[derive(Diagnostic)]
22#[diag(attr_parsing_expected_one_cfg_pattern, code = E0536)]
23pub(crate) struct ExpectedOneCfgPattern {
24    #[primary_span]
25    pub span: Span,
26}
27
28#[derive(Diagnostic)]
29#[diag(attr_parsing_invalid_predicate, code = E0537)]
30pub(crate) struct InvalidPredicate {
31    #[primary_span]
32    pub span: Span,
33
34    pub predicate: String,
35}
36
37/// Error code: E0541
38pub(crate) struct UnknownMetaItem<'a> {
39    pub span: Span,
40    pub item: String,
41    pub expected: &'a [&'a str],
42}
43
44// Manual implementation to be able to format `expected` items correctly.
45impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnknownMetaItem<'_> {
46    fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
47        let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
48        Diag::new(dcx, level, fluent::attr_parsing_unknown_meta_item)
49            .with_span(self.span)
50            .with_code(E0541)
51            .with_arg("item", self.item)
52            .with_arg("expected", expected.join(", "))
53            .with_span_label(self.span, fluent::attr_parsing_label)
54    }
55}
56
57#[derive(Diagnostic)]
58#[diag(attr_parsing_missing_since, code = E0542)]
59pub(crate) struct MissingSince {
60    #[primary_span]
61    pub span: Span,
62}
63
64#[derive(Diagnostic)]
65#[diag(attr_parsing_missing_note, code = E0543)]
66pub(crate) struct MissingNote {
67    #[primary_span]
68    pub span: Span,
69}
70
71#[derive(Diagnostic)]
72#[diag(attr_parsing_multiple_stability_levels, code = E0544)]
73pub(crate) struct MultipleStabilityLevels {
74    #[primary_span]
75    pub span: Span,
76}
77
78#[derive(Diagnostic)]
79#[diag(attr_parsing_invalid_issue_string, code = E0545)]
80pub(crate) struct InvalidIssueString {
81    #[primary_span]
82    pub span: Span,
83
84    #[subdiagnostic]
85    pub cause: Option<InvalidIssueStringCause>,
86}
87
88// The error kinds of `IntErrorKind` are duplicated here in order to allow the messages to be
89// translatable.
90#[derive(Subdiagnostic)]
91pub(crate) enum InvalidIssueStringCause {
92    #[label(attr_parsing_must_not_be_zero)]
93    MustNotBeZero {
94        #[primary_span]
95        span: Span,
96    },
97
98    #[label(attr_parsing_empty)]
99    Empty {
100        #[primary_span]
101        span: Span,
102    },
103
104    #[label(attr_parsing_invalid_digit)]
105    InvalidDigit {
106        #[primary_span]
107        span: Span,
108    },
109
110    #[label(attr_parsing_pos_overflow)]
111    PosOverflow {
112        #[primary_span]
113        span: Span,
114    },
115
116    #[label(attr_parsing_neg_overflow)]
117    NegOverflow {
118        #[primary_span]
119        span: Span,
120    },
121}
122
123impl InvalidIssueStringCause {
124    pub(crate) fn from_int_error_kind(span: Span, kind: &IntErrorKind) -> Option<Self> {
125        match kind {
126            IntErrorKind::Empty => Some(Self::Empty { span }),
127            IntErrorKind::InvalidDigit => Some(Self::InvalidDigit { span }),
128            IntErrorKind::PosOverflow => Some(Self::PosOverflow { span }),
129            IntErrorKind::NegOverflow => Some(Self::NegOverflow { span }),
130            IntErrorKind::Zero => Some(Self::MustNotBeZero { span }),
131            _ => None,
132        }
133    }
134}
135
136#[derive(Diagnostic)]
137#[diag(attr_parsing_missing_feature, code = E0546)]
138pub(crate) struct MissingFeature {
139    #[primary_span]
140    pub span: Span,
141}
142
143#[derive(Diagnostic)]
144#[diag(attr_parsing_non_ident_feature, code = E0546)]
145pub(crate) struct NonIdentFeature {
146    #[primary_span]
147    pub span: Span,
148}
149
150#[derive(Diagnostic)]
151#[diag(attr_parsing_missing_issue, code = E0547)]
152pub(crate) struct MissingIssue {
153    #[primary_span]
154    pub span: Span,
155}
156
157// FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`?
158// It is more similar to `IncorrectReprFormatGeneric`.
159#[derive(Diagnostic)]
160#[diag(attr_parsing_incorrect_repr_format_packed_one_or_zero_arg, code = E0552)]
161pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg {
162    #[primary_span]
163    pub span: Span,
164}
165#[derive(Diagnostic)]
166#[diag(attr_parsing_incorrect_repr_format_packed_expect_integer, code = E0552)]
167pub(crate) struct IncorrectReprFormatPackedExpectInteger {
168    #[primary_span]
169    pub span: Span,
170}
171
172#[derive(Diagnostic)]
173#[diag(attr_parsing_invalid_repr_hint_no_paren, code = E0552)]
174pub(crate) struct InvalidReprHintNoParen {
175    #[primary_span]
176    pub span: Span,
177
178    pub name: Symbol,
179}
180
181#[derive(Diagnostic)]
182#[diag(attr_parsing_invalid_repr_hint_no_value, code = E0552)]
183pub(crate) struct InvalidReprHintNoValue {
184    #[primary_span]
185    pub span: Span,
186
187    pub name: Symbol,
188}
189
190/// Error code: E0565
191// FIXME(jdonszelmann): slowly phased out
192pub(crate) struct UnsupportedLiteral {
193    pub span: Span,
194    pub reason: UnsupportedLiteralReason,
195    pub is_bytestr: bool,
196    pub start_point_span: Span,
197}
198
199impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral {
200    fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
201        let mut diag = Diag::new(
202            dcx,
203            level,
204            match self.reason {
205                UnsupportedLiteralReason::Generic => {
206                    fluent::attr_parsing_unsupported_literal_generic
207                }
208                UnsupportedLiteralReason::CfgString => {
209                    fluent::attr_parsing_unsupported_literal_cfg_string
210                }
211                UnsupportedLiteralReason::CfgBoolean => {
212                    fluent::attr_parsing_unsupported_literal_cfg_boolean
213                }
214            },
215        );
216        diag.span(self.span);
217        diag.code(E0565);
218        if self.is_bytestr {
219            diag.span_suggestion(
220                self.start_point_span,
221                fluent::attr_parsing_unsupported_literal_suggestion,
222                "",
223                Applicability::MaybeIncorrect,
224            );
225        }
226        diag
227    }
228}
229
230#[derive(Diagnostic)]
231#[diag(attr_parsing_invalid_repr_align_need_arg, code = E0589)]
232pub(crate) struct InvalidReprAlignNeedArg {
233    #[primary_span]
234    #[suggestion(code = "align(...)", applicability = "has-placeholders")]
235    pub span: Span,
236}
237
238#[derive(Diagnostic)]
239#[diag(attr_parsing_invalid_repr_generic, code = E0589)]
240pub(crate) struct InvalidReprGeneric<'a> {
241    #[primary_span]
242    pub span: Span,
243
244    pub repr_arg: String,
245    pub error_part: &'a str,
246}
247
248#[derive(Diagnostic)]
249#[diag(attr_parsing_incorrect_repr_format_align_one_arg, code = E0693)]
250pub(crate) struct IncorrectReprFormatAlignOneArg {
251    #[primary_span]
252    pub span: Span,
253}
254
255#[derive(Diagnostic)]
256#[diag(attr_parsing_incorrect_repr_format_expect_literal_integer, code = E0693)]
257pub(crate) struct IncorrectReprFormatExpectInteger {
258    #[primary_span]
259    pub span: Span,
260}
261
262#[derive(Diagnostic)]
263#[diag(attr_parsing_incorrect_repr_format_generic, code = E0693)]
264pub(crate) struct IncorrectReprFormatGeneric {
265    #[primary_span]
266    pub span: Span,
267
268    pub repr_arg: Symbol,
269
270    #[subdiagnostic]
271    pub cause: Option<IncorrectReprFormatGenericCause>,
272}
273
274#[derive(Subdiagnostic)]
275pub(crate) enum IncorrectReprFormatGenericCause {
276    #[suggestion(
277        attr_parsing_suggestion,
278        code = "{name}({value})",
279        applicability = "machine-applicable"
280    )]
281    Int {
282        #[primary_span]
283        span: Span,
284
285        #[skip_arg]
286        name: Symbol,
287
288        #[skip_arg]
289        value: u128,
290    },
291
292    #[suggestion(
293        attr_parsing_suggestion,
294        code = "{name}({value})",
295        applicability = "machine-applicable"
296    )]
297    Symbol {
298        #[primary_span]
299        span: Span,
300
301        #[skip_arg]
302        name: Symbol,
303
304        #[skip_arg]
305        value: Symbol,
306    },
307}
308
309impl IncorrectReprFormatGenericCause {
310    pub(crate) fn from_lit_kind(span: Span, kind: &ast::LitKind, name: Symbol) -> Option<Self> {
311        match *kind {
312            ast::LitKind::Int(value, ast::LitIntType::Unsuffixed) => {
313                Some(Self::Int { span, name, value: value.get() })
314            }
315            ast::LitKind::Str(value, _) => Some(Self::Symbol { span, name, value }),
316            _ => None,
317        }
318    }
319}
320
321#[derive(Diagnostic)]
322#[diag(attr_parsing_rustc_promotable_pairing, code = E0717)]
323pub(crate) struct RustcPromotablePairing {
324    #[primary_span]
325    pub span: Span,
326}
327
328#[derive(Diagnostic)]
329#[diag(attr_parsing_rustc_allowed_unstable_pairing, code = E0789)]
330pub(crate) struct RustcAllowedUnstablePairing {
331    #[primary_span]
332    pub span: Span,
333}
334
335#[derive(Diagnostic)]
336#[diag(attr_parsing_cfg_predicate_identifier)]
337pub(crate) struct CfgPredicateIdentifier {
338    #[primary_span]
339    pub span: Span,
340}
341
342#[derive(Diagnostic)]
343#[diag(attr_parsing_deprecated_item_suggestion)]
344pub(crate) struct DeprecatedItemSuggestion {
345    #[primary_span]
346    pub span: Span,
347
348    #[help]
349    pub is_nightly: bool,
350
351    #[note]
352    pub details: (),
353}
354
355#[derive(Diagnostic)]
356#[diag(attr_parsing_expected_single_version_literal)]
357pub(crate) struct ExpectedSingleVersionLiteral {
358    #[primary_span]
359    pub span: Span,
360}
361
362#[derive(Diagnostic)]
363#[diag(attr_parsing_expected_version_literal)]
364pub(crate) struct ExpectedVersionLiteral {
365    #[primary_span]
366    pub span: Span,
367}
368
369#[derive(Diagnostic)]
370#[diag(attr_parsing_expects_feature_list)]
371pub(crate) struct ExpectsFeatureList {
372    #[primary_span]
373    pub span: Span,
374
375    pub name: String,
376}
377
378#[derive(Diagnostic)]
379#[diag(attr_parsing_expects_features)]
380pub(crate) struct ExpectsFeatures {
381    #[primary_span]
382    pub span: Span,
383
384    pub name: String,
385}
386
387#[derive(Diagnostic)]
388#[diag(attr_parsing_invalid_since)]
389pub(crate) struct InvalidSince {
390    #[primary_span]
391    pub span: Span,
392}
393
394#[derive(Diagnostic)]
395#[diag(attr_parsing_soft_no_args)]
396pub(crate) struct SoftNoArgs {
397    #[primary_span]
398    pub span: Span,
399}
400
401#[derive(Diagnostic)]
402#[diag(attr_parsing_unknown_version_literal)]
403pub(crate) struct UnknownVersionLiteral {
404    #[primary_span]
405    pub span: Span,
406}
407
408// FIXME(jdonszelmann) duplicated from `rustc_passes`, remove once `check_attr` is integrated.
409#[derive(Diagnostic)]
410#[diag(attr_parsing_unused_multiple)]
411pub(crate) struct UnusedMultiple {
412    #[primary_span]
413    #[suggestion(code = "", applicability = "machine-applicable")]
414    pub this: Span,
415    #[note]
416    pub other: Span,
417    pub name: Symbol,
418}
419
420#[derive(LintDiagnostic)]
421#[diag(attr_parsing_unused_duplicate)]
422pub(crate) struct UnusedDuplicate {
423    #[suggestion(code = "", applicability = "machine-applicable")]
424    pub this: Span,
425    #[note]
426    pub other: Span,
427    #[warning]
428    pub warning: bool,
429}
430
431// FIXME(jdonszelmann): duplicated in rustc_lints, should be moved here completely.
432#[derive(LintDiagnostic)]
433#[diag(attr_parsing_ill_formed_attribute_input)]
434pub(crate) struct IllFormedAttributeInput {
435    pub num_suggestions: usize,
436    pub suggestions: DiagArgValue,
437}
438
439#[derive(Diagnostic)]
440#[diag(attr_parsing_ill_formed_attribute_input)]
441pub(crate) struct IllFormedAttributeInputLint {
442    #[primary_span]
443    pub span: Span,
444    pub num_suggestions: usize,
445    pub suggestions: DiagArgValue,
446}
447
448#[derive(Diagnostic)]
449#[diag(attr_parsing_null_on_export, code = E0648)]
450pub(crate) struct NullOnExport {
451    #[primary_span]
452    pub span: Span,
453}
454
455#[derive(Diagnostic)]
456#[diag(attr_parsing_null_on_link_section, code = E0648)]
457pub(crate) struct NullOnLinkSection {
458    #[primary_span]
459    pub span: Span,
460}
461
462#[derive(Diagnostic)]
463#[diag(attr_parsing_null_on_objc_class)]
464pub(crate) struct NullOnObjcClass {
465    #[primary_span]
466    pub span: Span,
467}
468
469#[derive(Diagnostic)]
470#[diag(attr_parsing_null_on_objc_selector)]
471pub(crate) struct NullOnObjcSelector {
472    #[primary_span]
473    pub span: Span,
474}
475
476#[derive(Diagnostic)]
477#[diag(attr_parsing_objc_class_expected_string_literal)]
478pub(crate) struct ObjcClassExpectedStringLiteral {
479    #[primary_span]
480    pub span: Span,
481}
482
483#[derive(Diagnostic)]
484#[diag(attr_parsing_objc_selector_expected_string_literal)]
485pub(crate) struct ObjcSelectorExpectedStringLiteral {
486    #[primary_span]
487    pub span: Span,
488}
489
490#[derive(Diagnostic)]
491#[diag(attr_parsing_stability_outside_std, code = E0734)]
492pub(crate) struct StabilityOutsideStd {
493    #[primary_span]
494    pub span: Span,
495}
496
497#[derive(Diagnostic)]
498#[diag(attr_parsing_empty_confusables)]
499pub(crate) struct EmptyConfusables {
500    #[primary_span]
501    pub span: Span,
502}
503
504#[derive(LintDiagnostic)]
505#[diag(attr_parsing_empty_attribute)]
506#[note]
507pub(crate) struct EmptyAttributeList {
508    #[suggestion(code = "", applicability = "machine-applicable")]
509    pub attr_span: Span,
510    pub attr_path: AttrPath,
511    pub valid_without_list: bool,
512}
513
514#[derive(LintDiagnostic)]
515#[diag(attr_parsing_invalid_target_lint)]
516#[warning]
517#[help]
518pub(crate) struct InvalidTargetLint {
519    pub name: AttrPath,
520    pub target: &'static str,
521    pub applied: DiagArgValue,
522    pub only: &'static str,
523    #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
524    pub attr_span: Span,
525}
526
527#[derive(Diagnostic)]
528#[help]
529#[diag(attr_parsing_invalid_target)]
530pub(crate) struct InvalidTarget {
531    #[primary_span]
532    #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
533    pub span: Span,
534    pub name: AttrPath,
535    pub target: &'static str,
536    pub applied: DiagArgValue,
537    pub only: &'static str,
538}
539
540#[derive(Diagnostic)]
541#[diag(attr_parsing_invalid_alignment_value, code = E0589)]
542pub(crate) struct InvalidAlignmentValue {
543    #[primary_span]
544    pub span: Span,
545    pub error_part: &'static str,
546}
547
548#[derive(Diagnostic)]
549#[diag(attr_parsing_repr_ident, code = E0565)]
550pub(crate) struct ReprIdent {
551    #[primary_span]
552    pub span: Span,
553}
554
555#[derive(Diagnostic)]
556#[diag(attr_parsing_unrecognized_repr_hint, code = E0552)]
557#[help]
558#[note]
559pub(crate) struct UnrecognizedReprHint {
560    #[primary_span]
561    pub span: Span,
562}
563
564#[derive(Diagnostic)]
565#[diag(attr_parsing_unstable_feature_bound_incompatible_stability)]
566#[help]
567pub(crate) struct UnstableFeatureBoundIncompatibleStability {
568    #[primary_span]
569    pub span: Span,
570}
571
572#[derive(Diagnostic)]
573#[diag(attr_parsing_naked_functions_incompatible_attribute, code = E0736)]
574pub(crate) struct NakedFunctionIncompatibleAttribute {
575    #[primary_span]
576    #[label]
577    pub span: Span,
578    #[label(attr_parsing_naked_attribute)]
579    pub naked_span: Span,
580    pub attr: String,
581}
582
583#[derive(Diagnostic)]
584#[diag(attr_parsing_link_ordinal_out_of_range)]
585#[note]
586pub(crate) struct LinkOrdinalOutOfRange {
587    #[primary_span]
588    pub span: Span,
589    pub ordinal: u128,
590}
591
592pub(crate) enum AttributeParseErrorReason<'a> {
593    ExpectedNoArgs,
594    ExpectedStringLiteral {
595        byte_string: Option<Span>,
596    },
597    ExpectedIntegerLiteral,
598    ExpectedAtLeastOneArgument,
599    ExpectedSingleArgument,
600    ExpectedList,
601    UnexpectedLiteral,
602    ExpectedNameValue(Option<Symbol>),
603    DuplicateKey(Symbol),
604    ExpectedSpecificArgument {
605        possibilities: &'a [Symbol],
606        strings: bool,
607        /// Should we tell the user to write a list when they didn't?
608        list: bool,
609    },
610    ExpectedIdentifier,
611}
612
613pub(crate) struct AttributeParseError<'a> {
614    pub(crate) span: Span,
615    pub(crate) attr_span: Span,
616    pub(crate) attr_style: AttrStyle,
617    pub(crate) template: AttributeTemplate,
618    pub(crate) attribute: AttrPath,
619    pub(crate) reason: AttributeParseErrorReason<'a>,
620}
621
622impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
623    fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
624        let name = self.attribute.to_string();
625
626        let mut diag = Diag::new(dcx, level, format!("malformed `{name}` attribute input"));
627        diag.span(self.attr_span);
628        diag.code(E0539);
629        match self.reason {
630            AttributeParseErrorReason::ExpectedStringLiteral { byte_string } => {
631                if let Some(start_point_span) = byte_string {
632                    diag.span_suggestion(
633                        start_point_span,
634                        fluent::attr_parsing_unsupported_literal_suggestion,
635                        "",
636                        Applicability::MaybeIncorrect,
637                    );
638                    diag.note("expected a normal string literal, not a byte string literal");
639
640                    return diag;
641                } else {
642                    diag.span_label(self.span, "expected a string literal here");
643                }
644            }
645            AttributeParseErrorReason::ExpectedIntegerLiteral => {
646                diag.span_label(self.span, "expected an integer literal here");
647            }
648            AttributeParseErrorReason::ExpectedSingleArgument => {
649                diag.span_label(self.span, "expected a single argument here");
650                diag.code(E0805);
651            }
652            AttributeParseErrorReason::ExpectedAtLeastOneArgument => {
653                diag.span_label(self.span, "expected at least 1 argument here");
654            }
655            AttributeParseErrorReason::ExpectedList => {
656                diag.span_label(self.span, "expected this to be a list");
657            }
658            AttributeParseErrorReason::DuplicateKey(key) => {
659                diag.span_label(self.span, format!("found `{key}` used as a key more than once"));
660                diag.code(E0538);
661            }
662            AttributeParseErrorReason::UnexpectedLiteral => {
663                diag.span_label(self.span, "didn't expect a literal here");
664                diag.code(E0565);
665            }
666            AttributeParseErrorReason::ExpectedNoArgs => {
667                diag.span_label(self.span, "didn't expect any arguments here");
668                diag.code(E0565);
669            }
670            AttributeParseErrorReason::ExpectedNameValue(None) => {
671                // If the span is the entire attribute, the suggestion we add below this match already contains enough information
672                if self.span != self.attr_span {
673                    diag.span_label(
674                        self.span,
675                        format!("expected this to be of the form `... = \"...\"`"),
676                    );
677                }
678            }
679            AttributeParseErrorReason::ExpectedNameValue(Some(name)) => {
680                diag.span_label(
681                    self.span,
682                    format!("expected this to be of the form `{name} = \"...\"`"),
683                );
684            }
685            AttributeParseErrorReason::ExpectedSpecificArgument {
686                possibilities,
687                strings,
688                list: false,
689            } => {
690                let quote = if strings { '"' } else { '`' };
691                match possibilities {
692                    &[] => {}
693                    &[x] => {
694                        diag.span_label(
695                            self.span,
696                            format!("the only valid argument here is {quote}{x}{quote}"),
697                        );
698                    }
699                    [first, second] => {
700                        diag.span_label(self.span, format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}"));
701                    }
702                    [first @ .., second_to_last, last] => {
703                        let mut res = String::new();
704                        for i in first {
705                            res.push_str(&format!("{quote}{i}{quote}, "));
706                        }
707                        res.push_str(&format!(
708                            "{quote}{second_to_last}{quote} or {quote}{last}{quote}"
709                        ));
710
711                        diag.span_label(self.span, format!("valid arguments are {res}"));
712                    }
713                }
714            }
715            AttributeParseErrorReason::ExpectedSpecificArgument {
716                possibilities,
717                strings,
718                list: true,
719            } => {
720                let quote = if strings { '"' } else { '`' };
721                match possibilities {
722                    &[] => {}
723                    &[x] => {
724                        diag.span_label(
725                            self.span,
726                            format!(
727                                "this attribute is only valid with {quote}{x}{quote} as an argument"
728                            ),
729                        );
730                    }
731                    [first, second] => {
732                        diag.span_label(self.span, format!("this attribute is only valid with either {quote}{first}{quote} or {quote}{second}{quote} as an argument"));
733                    }
734                    [first @ .., second_to_last, last] => {
735                        let mut res = String::new();
736                        for i in first {
737                            res.push_str(&format!("{quote}{i}{quote}, "));
738                        }
739                        res.push_str(&format!(
740                            "{quote}{second_to_last}{quote} or {quote}{last}{quote}"
741                        ));
742
743                        diag.span_label(self.span, format!("this attribute is only valid with one of the following arguments: {res}"));
744                    }
745                }
746            }
747            AttributeParseErrorReason::ExpectedIdentifier => {
748                diag.span_label(self.span, "expected a valid identifier here");
749            }
750        }
751
752        if let Some(link) = self.template.docs {
753            diag.note(format!("for more information, visit <{link}>"));
754        }
755        let suggestions = self.template.suggestions(self.attr_style, &name);
756
757        diag.span_suggestions(
758            self.attr_span,
759            if suggestions.len() == 1 {
760                "must be of the form"
761            } else {
762                "try changing it to one of the following valid forms of the attribute"
763            },
764            suggestions,
765            Applicability::HasPlaceholders,
766        );
767
768        diag
769    }
770}
771
772#[derive(Diagnostic)]
773#[diag(attr_parsing_invalid_attr_unsafe)]
774#[note]
775pub(crate) struct InvalidAttrUnsafe {
776    #[primary_span]
777    #[label]
778    pub span: Span,
779    pub name: Path,
780}
781
782#[derive(Diagnostic)]
783#[diag(attr_parsing_unsafe_attr_outside_unsafe)]
784pub(crate) struct UnsafeAttrOutsideUnsafe {
785    #[primary_span]
786    #[label]
787    pub span: Span,
788    #[subdiagnostic]
789    pub suggestion: UnsafeAttrOutsideUnsafeSuggestion,
790}
791
792#[derive(Subdiagnostic)]
793#[multipart_suggestion(
794    attr_parsing_unsafe_attr_outside_unsafe_suggestion,
795    applicability = "machine-applicable"
796)]
797pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion {
798    #[suggestion_part(code = "unsafe(")]
799    pub left: Span,
800    #[suggestion_part(code = ")")]
801    pub right: Span,
802}
803
804#[derive(Diagnostic)]
805#[diag(attr_parsing_meta_bad_delim)]
806pub(crate) struct MetaBadDelim {
807    #[primary_span]
808    pub span: Span,
809    #[subdiagnostic]
810    pub sugg: MetaBadDelimSugg,
811}
812
813#[derive(Subdiagnostic)]
814#[multipart_suggestion(
815    attr_parsing_meta_bad_delim_suggestion,
816    applicability = "machine-applicable"
817)]
818pub(crate) struct MetaBadDelimSugg {
819    #[suggestion_part(code = "(")]
820    pub open: Span,
821    #[suggestion_part(code = ")")]
822    pub close: Span,
823}
824
825#[derive(Diagnostic)]
826#[diag(attr_parsing_invalid_meta_item)]
827pub(crate) struct InvalidMetaItem {
828    #[primary_span]
829    pub span: Span,
830    pub descr: String,
831    #[subdiagnostic]
832    pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
833    #[subdiagnostic]
834    pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>,
835}
836
837#[derive(Subdiagnostic)]
838#[multipart_suggestion(attr_parsing_quote_ident_sugg, applicability = "machine-applicable")]
839pub(crate) struct InvalidMetaItemQuoteIdentSugg {
840    #[suggestion_part(code = "\"")]
841    pub before: Span,
842    #[suggestion_part(code = "\"")]
843    pub after: Span,
844}
845
846#[derive(Subdiagnostic)]
847#[multipart_suggestion(attr_parsing_remove_neg_sugg, applicability = "machine-applicable")]
848pub(crate) struct InvalidMetaItemRemoveNegSugg {
849    #[suggestion_part(code = "")]
850    pub negative_sign: Span,
851}
852
853#[derive(Diagnostic)]
854#[diag(attr_parsing_suffixed_literal_in_attribute)]
855#[help]
856pub(crate) struct SuffixedLiteralInAttribute {
857    #[primary_span]
858    pub span: Span,
859}
860
861#[derive(LintDiagnostic)]
862#[diag(attr_parsing_invalid_style)]
863pub(crate) struct InvalidAttrStyle {
864    pub name: AttrPath,
865    pub is_used_as_inner: bool,
866    #[note]
867    pub target_span: Option<Span>,
868    pub target: Target,
869}
870
871#[derive(Diagnostic)]
872#[diag(attr_parsing_empty_link_name, code = E0454)]
873pub(crate) struct EmptyLinkName {
874    #[primary_span]
875    #[label]
876    pub span: Span,
877}
878
879#[derive(Diagnostic)]
880#[diag(attr_parsing_link_framework_apple, code = E0455)]
881pub(crate) struct LinkFrameworkApple {
882    #[primary_span]
883    pub span: Span,
884}
885
886#[derive(Diagnostic)]
887#[diag(attr_parsing_incompatible_wasm_link)]
888pub(crate) struct IncompatibleWasmLink {
889    #[primary_span]
890    pub span: Span,
891}
892
893#[derive(Diagnostic)]
894#[diag(attr_parsing_link_requires_name, code = E0459)]
895pub(crate) struct LinkRequiresName {
896    #[primary_span]
897    #[label]
898    pub span: Span,
899}
900
901#[derive(Diagnostic)]
902#[diag(attr_parsing_raw_dylib_no_nul)]
903pub(crate) struct RawDylibNoNul {
904    #[primary_span]
905    pub span: Span,
906}
907
908#[derive(Diagnostic)]
909#[diag(attr_parsing_raw_dylib_only_windows, code = E0455)]
910pub(crate) struct RawDylibOnlyWindows {
911    #[primary_span]
912    pub span: Span,
913}
914
915#[derive(Diagnostic)]
916#[diag(attr_parsing_invalid_link_modifier)]
917pub(crate) struct InvalidLinkModifier {
918    #[primary_span]
919    pub span: Span,
920}
921
922#[derive(Diagnostic)]
923#[diag(attr_parsing_multiple_modifiers)]
924pub(crate) struct MultipleModifiers {
925    #[primary_span]
926    pub span: Span,
927    pub modifier: Symbol,
928}
929
930#[derive(Diagnostic)]
931#[diag(attr_parsing_import_name_type_x86)]
932pub(crate) struct ImportNameTypeX86 {
933    #[primary_span]
934    pub span: Span,
935}
936
937#[derive(Diagnostic)]
938#[diag(attr_parsing_bundle_needs_static)]
939pub(crate) struct BundleNeedsStatic {
940    #[primary_span]
941    pub span: Span,
942}
943
944#[derive(Diagnostic)]
945#[diag(attr_parsing_whole_archive_needs_static)]
946pub(crate) struct WholeArchiveNeedsStatic {
947    #[primary_span]
948    pub span: Span,
949}
950
951#[derive(Diagnostic)]
952#[diag(attr_parsing_as_needed_compatibility)]
953pub(crate) struct AsNeededCompatibility {
954    #[primary_span]
955    pub span: Span,
956}
957
958#[derive(Diagnostic)]
959#[diag(attr_parsing_import_name_type_raw)]
960pub(crate) struct ImportNameTypeRaw {
961    #[primary_span]
962    pub span: Span,
963}
964
965#[derive(Diagnostic)]
966#[diag(attr_parsing_limit_invalid)]
967pub(crate) struct LimitInvalid<'a> {
968    #[primary_span]
969    pub span: Span,
970    #[label]
971    pub value_span: Span,
972    pub error_str: &'a str,
973}