rustc_lint/
lints.rs

1#![allow(rustc::untranslatable_diagnostic)]
2use std::num::NonZero;
3
4use rustc_abi::ExternAbi;
5use rustc_errors::codes::*;
6use rustc_errors::{
7    Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag,
8    EmissionGuarantee, LintDiagnostic, MultiSpan, Subdiagnostic, SuggestionStyle,
9};
10use rustc_hir as hir;
11use rustc_hir::def::Namespace;
12use rustc_hir::def_id::DefId;
13use rustc_hir::intravisit::VisitorExt;
14use rustc_macros::{LintDiagnostic, Subdiagnostic};
15use rustc_middle::ty::inhabitedness::InhabitedPredicate;
16use rustc_middle::ty::{Clause, PolyExistentialTraitRef, Ty, TyCtxt};
17use rustc_session::Session;
18use rustc_session::lint::AmbiguityErrorDiag;
19use rustc_span::edition::Edition;
20use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym};
21
22use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds};
23use crate::errors::{OverruledAttributeSub, RequestedLevel};
24use crate::lifetime_syntax::LifetimeSyntaxCategories;
25use crate::{LateContext, fluent_generated as fluent};
26
27// array_into_iter.rs
28#[derive(LintDiagnostic)]
29#[diag(lint_shadowed_into_iter)]
30pub(crate) struct ShadowedIntoIterDiag {
31    pub target: &'static str,
32    pub edition: &'static str,
33    #[suggestion(lint_use_iter_suggestion, code = "iter", applicability = "machine-applicable")]
34    pub suggestion: Span,
35    #[subdiagnostic]
36    pub sub: Option<ShadowedIntoIterDiagSub>,
37}
38
39#[derive(Subdiagnostic)]
40pub(crate) enum ShadowedIntoIterDiagSub {
41    #[suggestion(lint_remove_into_iter_suggestion, code = "", applicability = "maybe-incorrect")]
42    RemoveIntoIter {
43        #[primary_span]
44        span: Span,
45    },
46    #[multipart_suggestion(
47        lint_use_explicit_into_iter_suggestion,
48        applicability = "maybe-incorrect"
49    )]
50    UseExplicitIntoIter {
51        #[suggestion_part(code = "IntoIterator::into_iter(")]
52        start_span: Span,
53        #[suggestion_part(code = ")")]
54        end_span: Span,
55    },
56}
57
58// autorefs.rs
59#[derive(LintDiagnostic)]
60#[diag(lint_implicit_unsafe_autorefs)]
61#[note]
62pub(crate) struct ImplicitUnsafeAutorefsDiag<'a> {
63    #[label(lint_raw_ptr)]
64    pub raw_ptr_span: Span,
65    pub raw_ptr_ty: Ty<'a>,
66    #[subdiagnostic]
67    pub origin: ImplicitUnsafeAutorefsOrigin<'a>,
68    #[subdiagnostic]
69    pub method: Option<ImplicitUnsafeAutorefsMethodNote>,
70    #[subdiagnostic]
71    pub suggestion: ImplicitUnsafeAutorefsSuggestion,
72}
73
74#[derive(Subdiagnostic)]
75pub(crate) enum ImplicitUnsafeAutorefsOrigin<'a> {
76    #[note(lint_autoref)]
77    Autoref {
78        #[primary_span]
79        autoref_span: Span,
80        autoref_ty: Ty<'a>,
81    },
82    #[note(lint_overloaded_deref)]
83    OverloadedDeref,
84}
85
86#[derive(Subdiagnostic)]
87#[note(lint_method_def)]
88pub(crate) struct ImplicitUnsafeAutorefsMethodNote {
89    #[primary_span]
90    pub def_span: Span,
91    pub method_name: Symbol,
92}
93
94#[derive(Subdiagnostic)]
95#[multipart_suggestion(lint_suggestion, applicability = "maybe-incorrect")]
96pub(crate) struct ImplicitUnsafeAutorefsSuggestion {
97    pub mutbl: &'static str,
98    pub deref: &'static str,
99    #[suggestion_part(code = "({mutbl}{deref}")]
100    pub start_span: Span,
101    #[suggestion_part(code = ")")]
102    pub end_span: Span,
103}
104
105// builtin.rs
106#[derive(LintDiagnostic)]
107#[diag(lint_builtin_while_true)]
108pub(crate) struct BuiltinWhileTrue {
109    #[suggestion(style = "short", code = "{replace}", applicability = "machine-applicable")]
110    pub suggestion: Span,
111    pub replace: String,
112}
113
114#[derive(LintDiagnostic)]
115#[diag(lint_builtin_non_shorthand_field_patterns)]
116pub(crate) struct BuiltinNonShorthandFieldPatterns {
117    pub ident: Ident,
118    #[suggestion(code = "{prefix}{ident}", applicability = "machine-applicable")]
119    pub suggestion: Span,
120    pub prefix: &'static str,
121}
122
123#[derive(LintDiagnostic)]
124pub(crate) enum BuiltinUnsafe {
125    #[diag(lint_builtin_allow_internal_unsafe)]
126    AllowInternalUnsafe,
127    #[diag(lint_builtin_unsafe_block)]
128    UnsafeBlock,
129    #[diag(lint_builtin_unsafe_extern_block)]
130    UnsafeExternBlock,
131    #[diag(lint_builtin_unsafe_trait)]
132    UnsafeTrait,
133    #[diag(lint_builtin_unsafe_impl)]
134    UnsafeImpl,
135    #[diag(lint_builtin_no_mangle_fn)]
136    #[note(lint_builtin_overridden_symbol_name)]
137    NoMangleFn,
138    #[diag(lint_builtin_export_name_fn)]
139    #[note(lint_builtin_overridden_symbol_name)]
140    ExportNameFn,
141    #[diag(lint_builtin_link_section_fn)]
142    #[note(lint_builtin_overridden_symbol_section)]
143    LinkSectionFn,
144    #[diag(lint_builtin_no_mangle_static)]
145    #[note(lint_builtin_overridden_symbol_name)]
146    NoMangleStatic,
147    #[diag(lint_builtin_export_name_static)]
148    #[note(lint_builtin_overridden_symbol_name)]
149    ExportNameStatic,
150    #[diag(lint_builtin_link_section_static)]
151    #[note(lint_builtin_overridden_symbol_section)]
152    LinkSectionStatic,
153    #[diag(lint_builtin_no_mangle_method)]
154    #[note(lint_builtin_overridden_symbol_name)]
155    NoMangleMethod,
156    #[diag(lint_builtin_export_name_method)]
157    #[note(lint_builtin_overridden_symbol_name)]
158    ExportNameMethod,
159    #[diag(lint_builtin_decl_unsafe_fn)]
160    DeclUnsafeFn,
161    #[diag(lint_builtin_decl_unsafe_method)]
162    DeclUnsafeMethod,
163    #[diag(lint_builtin_impl_unsafe_method)]
164    ImplUnsafeMethod,
165    #[diag(lint_builtin_global_asm)]
166    #[note(lint_builtin_global_macro_unsafety)]
167    GlobalAsm,
168}
169
170#[derive(LintDiagnostic)]
171#[diag(lint_builtin_missing_doc)]
172pub(crate) struct BuiltinMissingDoc<'a> {
173    pub article: &'a str,
174    pub desc: &'a str,
175}
176
177#[derive(LintDiagnostic)]
178#[diag(lint_builtin_missing_copy_impl)]
179pub(crate) struct BuiltinMissingCopyImpl;
180
181pub(crate) struct BuiltinMissingDebugImpl<'a> {
182    pub tcx: TyCtxt<'a>,
183    pub def_id: DefId,
184}
185
186// Needed for def_path_str
187impl<'a> LintDiagnostic<'a, ()> for BuiltinMissingDebugImpl<'_> {
188    fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) {
189        diag.primary_message(fluent::lint_builtin_missing_debug_impl);
190        diag.arg("debug", self.tcx.def_path_str(self.def_id));
191    }
192}
193
194#[derive(LintDiagnostic)]
195#[diag(lint_builtin_anonymous_params)]
196pub(crate) struct BuiltinAnonymousParams<'a> {
197    #[suggestion(code = "_: {ty_snip}")]
198    pub suggestion: (Span, Applicability),
199    pub ty_snip: &'a str,
200}
201
202#[derive(LintDiagnostic)]
203#[diag(lint_builtin_unused_doc_comment)]
204pub(crate) struct BuiltinUnusedDocComment<'a> {
205    pub kind: &'a str,
206    #[label]
207    pub label: Span,
208    #[subdiagnostic]
209    pub sub: BuiltinUnusedDocCommentSub,
210}
211
212#[derive(Subdiagnostic)]
213pub(crate) enum BuiltinUnusedDocCommentSub {
214    #[help(lint_plain_help)]
215    PlainHelp,
216    #[help(lint_block_help)]
217    BlockHelp,
218}
219
220#[derive(LintDiagnostic)]
221#[diag(lint_builtin_no_mangle_generic)]
222pub(crate) struct BuiltinNoMangleGeneric {
223    // Use of `#[no_mangle]` suggests FFI intent; correct
224    // fix may be to monomorphize source by hand
225    #[suggestion(style = "short", code = "", applicability = "maybe-incorrect")]
226    pub suggestion: Span,
227}
228
229#[derive(LintDiagnostic)]
230#[diag(lint_builtin_const_no_mangle)]
231pub(crate) struct BuiltinConstNoMangle {
232    #[suggestion(code = "pub static", applicability = "machine-applicable")]
233    pub suggestion: Span,
234}
235
236#[derive(LintDiagnostic)]
237#[diag(lint_builtin_mutable_transmutes)]
238pub(crate) struct BuiltinMutablesTransmutes;
239
240#[derive(LintDiagnostic)]
241#[diag(lint_builtin_unstable_features)]
242pub(crate) struct BuiltinUnstableFeatures;
243
244// lint_ungated_async_fn_track_caller
245pub(crate) struct BuiltinUngatedAsyncFnTrackCaller<'a> {
246    pub label: Span,
247    pub session: &'a Session,
248}
249
250impl<'a> LintDiagnostic<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> {
251    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
252        diag.primary_message(fluent::lint_ungated_async_fn_track_caller);
253        diag.span_label(self.label, fluent::lint_label);
254        rustc_session::parse::add_feature_diagnostics(
255            diag,
256            self.session,
257            sym::async_fn_track_caller,
258        );
259    }
260}
261
262#[derive(LintDiagnostic)]
263#[diag(lint_builtin_unreachable_pub)]
264pub(crate) struct BuiltinUnreachablePub<'a> {
265    pub what: &'a str,
266    pub new_vis: &'a str,
267    #[suggestion(code = "{new_vis}")]
268    pub suggestion: (Span, Applicability),
269    #[help]
270    pub help: bool,
271}
272
273#[derive(LintDiagnostic)]
274#[diag(lint_macro_expr_fragment_specifier_2024_migration)]
275pub(crate) struct MacroExprFragment2024 {
276    #[suggestion(code = "expr_2021", applicability = "machine-applicable")]
277    pub suggestion: Span,
278}
279
280pub(crate) struct BuiltinTypeAliasBounds<'hir> {
281    pub in_where_clause: bool,
282    pub label: Span,
283    pub enable_feat_help: bool,
284    pub suggestions: Vec<(Span, String)>,
285    pub preds: &'hir [hir::WherePredicate<'hir>],
286    pub ty: Option<&'hir hir::Ty<'hir>>,
287}
288
289impl<'a> LintDiagnostic<'a, ()> for BuiltinTypeAliasBounds<'_> {
290    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
291        diag.primary_message(if self.in_where_clause {
292            fluent::lint_builtin_type_alias_bounds_where_clause
293        } else {
294            fluent::lint_builtin_type_alias_bounds_param_bounds
295        });
296        diag.span_label(self.label, fluent::lint_builtin_type_alias_bounds_label);
297        diag.note(fluent::lint_builtin_type_alias_bounds_limitation_note);
298        if self.enable_feat_help {
299            diag.help(fluent::lint_builtin_type_alias_bounds_enable_feat_help);
300        }
301
302        // We perform the walk in here instead of in `<TypeAliasBounds as LateLintPass>` to
303        // avoid doing throwaway work in case the lint ends up getting suppressed.
304        let mut collector = ShorthandAssocTyCollector { qselves: Vec::new() };
305        if let Some(ty) = self.ty {
306            collector.visit_ty_unambig(ty);
307        }
308
309        let affect_object_lifetime_defaults = self
310            .preds
311            .iter()
312            .filter(|pred| pred.kind.in_where_clause() == self.in_where_clause)
313            .any(|pred| TypeAliasBounds::affects_object_lifetime_defaults(pred));
314
315        // If there are any shorthand assoc tys, then the bounds can't be removed automatically.
316        // The user first needs to fully qualify the assoc tys.
317        let applicability = if !collector.qselves.is_empty() || affect_object_lifetime_defaults {
318            Applicability::MaybeIncorrect
319        } else {
320            Applicability::MachineApplicable
321        };
322
323        diag.arg("count", self.suggestions.len());
324        diag.multipart_suggestion(fluent::lint_suggestion, self.suggestions, applicability);
325
326        // Suggest fully qualifying paths of the form `T::Assoc` with `T` type param via
327        // `<T as /* Trait */>::Assoc` to remove their reliance on any type param bounds.
328        //
329        // Instead of attempting to figure out the necessary trait ref, just use a
330        // placeholder. Since we don't record type-dependent resolutions for non-body
331        // items like type aliases, we can't simply deduce the corresp. trait from
332        // the HIR path alone without rerunning parts of HIR ty lowering here
333        // (namely `probe_single_ty_param_bound_for_assoc_ty`) which is infeasible.
334        //
335        // (We could employ some simple heuristics but that's likely not worth it).
336        for qself in collector.qselves {
337            diag.multipart_suggestion(
338                fluent::lint_builtin_type_alias_bounds_qualify_assoc_tys_sugg,
339                vec![
340                    (qself.shrink_to_lo(), "<".into()),
341                    (qself.shrink_to_hi(), " as /* Trait */>".into()),
342                ],
343                Applicability::HasPlaceholders,
344            );
345        }
346    }
347}
348
349#[derive(LintDiagnostic)]
350#[diag(lint_builtin_trivial_bounds)]
351pub(crate) struct BuiltinTrivialBounds<'a> {
352    pub predicate_kind_name: &'a str,
353    pub predicate: Clause<'a>,
354}
355
356#[derive(LintDiagnostic)]
357#[diag(lint_builtin_double_negations)]
358#[note(lint_note)]
359#[note(lint_note_decrement)]
360pub(crate) struct BuiltinDoubleNegations {
361    #[subdiagnostic]
362    pub add_parens: BuiltinDoubleNegationsAddParens,
363}
364
365#[derive(Subdiagnostic)]
366#[multipart_suggestion(lint_add_parens_suggestion, applicability = "maybe-incorrect")]
367pub(crate) struct BuiltinDoubleNegationsAddParens {
368    #[suggestion_part(code = "(")]
369    pub start_span: Span,
370    #[suggestion_part(code = ")")]
371    pub end_span: Span,
372}
373
374#[derive(LintDiagnostic)]
375pub(crate) enum BuiltinEllipsisInclusiveRangePatternsLint {
376    #[diag(lint_builtin_ellipsis_inclusive_range_patterns)]
377    Parenthesise {
378        #[suggestion(code = "{replace}", applicability = "machine-applicable")]
379        suggestion: Span,
380        replace: String,
381    },
382    #[diag(lint_builtin_ellipsis_inclusive_range_patterns)]
383    NonParenthesise {
384        #[suggestion(style = "short", code = "..=", applicability = "machine-applicable")]
385        suggestion: Span,
386    },
387}
388
389#[derive(LintDiagnostic)]
390#[diag(lint_builtin_keyword_idents)]
391pub(crate) struct BuiltinKeywordIdents {
392    pub kw: Ident,
393    pub next: Edition,
394    #[suggestion(code = "{prefix}r#{kw}", applicability = "machine-applicable")]
395    pub suggestion: Span,
396    pub prefix: &'static str,
397}
398
399#[derive(LintDiagnostic)]
400#[diag(lint_builtin_explicit_outlives)]
401pub(crate) struct BuiltinExplicitOutlives {
402    pub count: usize,
403    #[subdiagnostic]
404    pub suggestion: BuiltinExplicitOutlivesSuggestion,
405}
406
407#[derive(Subdiagnostic)]
408#[multipart_suggestion(lint_suggestion)]
409pub(crate) struct BuiltinExplicitOutlivesSuggestion {
410    #[suggestion_part(code = "")]
411    pub spans: Vec<Span>,
412    #[applicability]
413    pub applicability: Applicability,
414}
415
416#[derive(LintDiagnostic)]
417#[diag(lint_builtin_incomplete_features)]
418pub(crate) struct BuiltinIncompleteFeatures {
419    pub name: Symbol,
420    #[subdiagnostic]
421    pub note: Option<BuiltinFeatureIssueNote>,
422    #[subdiagnostic]
423    pub help: Option<BuiltinIncompleteFeaturesHelp>,
424}
425
426#[derive(LintDiagnostic)]
427#[diag(lint_builtin_internal_features)]
428#[note]
429pub(crate) struct BuiltinInternalFeatures {
430    pub name: Symbol,
431}
432
433#[derive(Subdiagnostic)]
434#[help(lint_help)]
435pub(crate) struct BuiltinIncompleteFeaturesHelp;
436
437#[derive(Subdiagnostic)]
438#[note(lint_note)]
439pub(crate) struct BuiltinFeatureIssueNote {
440    pub n: NonZero<u32>,
441}
442
443pub(crate) struct BuiltinUnpermittedTypeInit<'a> {
444    pub msg: DiagMessage,
445    pub ty: Ty<'a>,
446    pub label: Span,
447    pub sub: BuiltinUnpermittedTypeInitSub,
448    pub tcx: TyCtxt<'a>,
449}
450
451impl<'a> LintDiagnostic<'a, ()> for BuiltinUnpermittedTypeInit<'_> {
452    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
453        diag.primary_message(self.msg);
454        diag.arg("ty", self.ty);
455        diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label);
456        if let InhabitedPredicate::True = self.ty.inhabited_predicate(self.tcx) {
457            // Only suggest late `MaybeUninit::assume_init` initialization if the type is inhabited.
458            diag.span_label(
459                self.label,
460                fluent::lint_builtin_unpermitted_type_init_label_suggestion,
461            );
462        }
463        self.sub.add_to_diag(diag);
464    }
465}
466
467// FIXME(davidtwco): make translatable
468pub(crate) struct BuiltinUnpermittedTypeInitSub {
469    pub err: InitError,
470}
471
472impl Subdiagnostic for BuiltinUnpermittedTypeInitSub {
473    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
474        let mut err = self.err;
475        loop {
476            if let Some(span) = err.span {
477                diag.span_note(span, err.message);
478            } else {
479                diag.note(err.message);
480            }
481            if let Some(e) = err.nested {
482                err = *e;
483            } else {
484                break;
485            }
486        }
487    }
488}
489
490#[derive(LintDiagnostic)]
491pub(crate) enum BuiltinClashingExtern<'a> {
492    #[diag(lint_builtin_clashing_extern_same_name)]
493    SameName {
494        this: Symbol,
495        orig: Symbol,
496        #[label(lint_previous_decl_label)]
497        previous_decl_label: Span,
498        #[label(lint_mismatch_label)]
499        mismatch_label: Span,
500        #[subdiagnostic]
501        sub: BuiltinClashingExternSub<'a>,
502    },
503    #[diag(lint_builtin_clashing_extern_diff_name)]
504    DiffName {
505        this: Symbol,
506        orig: Symbol,
507        #[label(lint_previous_decl_label)]
508        previous_decl_label: Span,
509        #[label(lint_mismatch_label)]
510        mismatch_label: Span,
511        #[subdiagnostic]
512        sub: BuiltinClashingExternSub<'a>,
513    },
514}
515
516// FIXME(davidtwco): translatable expected/found
517pub(crate) struct BuiltinClashingExternSub<'a> {
518    pub tcx: TyCtxt<'a>,
519    pub expected: Ty<'a>,
520    pub found: Ty<'a>,
521}
522
523impl Subdiagnostic for BuiltinClashingExternSub<'_> {
524    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
525        let mut expected_str = DiagStyledString::new();
526        expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false);
527        let mut found_str = DiagStyledString::new();
528        found_str.push(self.found.fn_sig(self.tcx).to_string(), true);
529        diag.note_expected_found("", expected_str, "", found_str);
530    }
531}
532
533#[derive(LintDiagnostic)]
534#[diag(lint_builtin_deref_nullptr)]
535pub(crate) struct BuiltinDerefNullptr {
536    #[label]
537    pub label: Span,
538}
539
540// FIXME: migrate fluent::lint::builtin_asm_labels
541
542#[derive(LintDiagnostic)]
543pub(crate) enum BuiltinSpecialModuleNameUsed {
544    #[diag(lint_builtin_special_module_name_used_lib)]
545    #[note]
546    #[help]
547    Lib,
548    #[diag(lint_builtin_special_module_name_used_main)]
549    #[note]
550    Main,
551}
552
553// deref_into_dyn_supertrait.rs
554#[derive(LintDiagnostic)]
555#[diag(lint_supertrait_as_deref_target)]
556pub(crate) struct SupertraitAsDerefTarget<'a> {
557    pub self_ty: Ty<'a>,
558    pub supertrait_principal: PolyExistentialTraitRef<'a>,
559    pub target_principal: PolyExistentialTraitRef<'a>,
560    #[label]
561    pub label: Span,
562    #[subdiagnostic]
563    pub label2: Option<SupertraitAsDerefTargetLabel>,
564}
565
566#[derive(Subdiagnostic)]
567#[label(lint_label2)]
568pub(crate) struct SupertraitAsDerefTargetLabel {
569    #[primary_span]
570    pub label: Span,
571}
572
573// enum_intrinsics_non_enums.rs
574#[derive(LintDiagnostic)]
575#[diag(lint_enum_intrinsics_mem_discriminant)]
576pub(crate) struct EnumIntrinsicsMemDiscriminate<'a> {
577    pub ty_param: Ty<'a>,
578    #[note]
579    pub note: Span,
580}
581
582#[derive(LintDiagnostic)]
583#[diag(lint_enum_intrinsics_mem_variant)]
584#[note]
585pub(crate) struct EnumIntrinsicsMemVariant<'a> {
586    pub ty_param: Ty<'a>,
587}
588
589// expect.rs
590#[derive(LintDiagnostic)]
591#[diag(lint_expectation)]
592pub(crate) struct Expectation {
593    #[subdiagnostic]
594    pub rationale: Option<ExpectationNote>,
595    #[note]
596    pub note: bool,
597}
598
599#[derive(Subdiagnostic)]
600#[note(lint_rationale)]
601pub(crate) struct ExpectationNote {
602    pub rationale: Symbol,
603}
604
605// ptr_nulls.rs
606#[derive(LintDiagnostic)]
607pub(crate) enum UselessPtrNullChecksDiag<'a> {
608    #[diag(lint_useless_ptr_null_checks_fn_ptr)]
609    #[help]
610    FnPtr {
611        orig_ty: Ty<'a>,
612        #[label]
613        label: Span,
614    },
615    #[diag(lint_useless_ptr_null_checks_ref)]
616    Ref {
617        orig_ty: Ty<'a>,
618        #[label]
619        label: Span,
620    },
621    #[diag(lint_useless_ptr_null_checks_fn_ret)]
622    FnRet { fn_name: Ident },
623}
624
625#[derive(LintDiagnostic)]
626pub(crate) enum InvalidNullArgumentsDiag {
627    #[diag(lint_invalid_null_arguments)]
628    #[help(lint_doc)]
629    NullPtrInline {
630        #[label(lint_origin)]
631        null_span: Span,
632    },
633    #[diag(lint_invalid_null_arguments)]
634    #[help(lint_doc)]
635    NullPtrThroughBinding {
636        #[note(lint_origin)]
637        null_span: Span,
638    },
639}
640
641// for_loops_over_fallibles.rs
642#[derive(LintDiagnostic)]
643#[diag(lint_for_loops_over_fallibles)]
644pub(crate) struct ForLoopsOverFalliblesDiag<'a> {
645    pub article: &'static str,
646    pub ref_prefix: &'static str,
647    pub ty: &'static str,
648    #[subdiagnostic]
649    pub sub: ForLoopsOverFalliblesLoopSub<'a>,
650    #[subdiagnostic]
651    pub question_mark: Option<ForLoopsOverFalliblesQuestionMark>,
652    #[subdiagnostic]
653    pub suggestion: ForLoopsOverFalliblesSuggestion<'a>,
654}
655
656#[derive(Subdiagnostic)]
657pub(crate) enum ForLoopsOverFalliblesLoopSub<'a> {
658    #[suggestion(lint_remove_next, code = ".by_ref()", applicability = "maybe-incorrect")]
659    RemoveNext {
660        #[primary_span]
661        suggestion: Span,
662        recv_snip: String,
663    },
664    #[multipart_suggestion(lint_use_while_let, applicability = "maybe-incorrect")]
665    UseWhileLet {
666        #[suggestion_part(code = "while let {var}(")]
667        start_span: Span,
668        #[suggestion_part(code = ") = ")]
669        end_span: Span,
670        var: &'a str,
671    },
672}
673
674#[derive(Subdiagnostic)]
675#[suggestion(lint_use_question_mark, code = "?", applicability = "maybe-incorrect")]
676pub(crate) struct ForLoopsOverFalliblesQuestionMark {
677    #[primary_span]
678    pub suggestion: Span,
679}
680
681#[derive(Subdiagnostic)]
682#[multipart_suggestion(lint_suggestion, applicability = "maybe-incorrect")]
683pub(crate) struct ForLoopsOverFalliblesSuggestion<'a> {
684    pub var: &'a str,
685    #[suggestion_part(code = "if let {var}(")]
686    pub start_span: Span,
687    #[suggestion_part(code = ") = ")]
688    pub end_span: Span,
689}
690
691#[derive(Subdiagnostic)]
692pub(crate) enum UseLetUnderscoreIgnoreSuggestion {
693    #[note(lint_use_let_underscore_ignore_suggestion)]
694    Note,
695    #[multipart_suggestion(
696        lint_use_let_underscore_ignore_suggestion,
697        style = "verbose",
698        applicability = "maybe-incorrect"
699    )]
700    Suggestion {
701        #[suggestion_part(code = "let _ = ")]
702        start_span: Span,
703        #[suggestion_part(code = "")]
704        end_span: Span,
705    },
706}
707
708// drop_forget_useless.rs
709#[derive(LintDiagnostic)]
710#[diag(lint_dropping_references)]
711pub(crate) struct DropRefDiag<'a> {
712    pub arg_ty: Ty<'a>,
713    #[label]
714    pub label: Span,
715    #[subdiagnostic]
716    pub sugg: UseLetUnderscoreIgnoreSuggestion,
717}
718
719#[derive(LintDiagnostic)]
720#[diag(lint_dropping_copy_types)]
721pub(crate) struct DropCopyDiag<'a> {
722    pub arg_ty: Ty<'a>,
723    #[label]
724    pub label: Span,
725    #[subdiagnostic]
726    pub sugg: UseLetUnderscoreIgnoreSuggestion,
727}
728
729#[derive(LintDiagnostic)]
730#[diag(lint_forgetting_references)]
731pub(crate) struct ForgetRefDiag<'a> {
732    pub arg_ty: Ty<'a>,
733    #[label]
734    pub label: Span,
735    #[subdiagnostic]
736    pub sugg: UseLetUnderscoreIgnoreSuggestion,
737}
738
739#[derive(LintDiagnostic)]
740#[diag(lint_forgetting_copy_types)]
741pub(crate) struct ForgetCopyDiag<'a> {
742    pub arg_ty: Ty<'a>,
743    #[label]
744    pub label: Span,
745    #[subdiagnostic]
746    pub sugg: UseLetUnderscoreIgnoreSuggestion,
747}
748
749#[derive(LintDiagnostic)]
750#[diag(lint_undropped_manually_drops)]
751pub(crate) struct UndroppedManuallyDropsDiag<'a> {
752    pub arg_ty: Ty<'a>,
753    #[label]
754    pub label: Span,
755    #[subdiagnostic]
756    pub suggestion: UndroppedManuallyDropsSuggestion,
757}
758
759#[derive(Subdiagnostic)]
760#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable")]
761pub(crate) struct UndroppedManuallyDropsSuggestion {
762    #[suggestion_part(code = "std::mem::ManuallyDrop::into_inner(")]
763    pub start_span: Span,
764    #[suggestion_part(code = ")")]
765    pub end_span: Span,
766}
767
768// invalid_from_utf8.rs
769#[derive(LintDiagnostic)]
770pub(crate) enum InvalidFromUtf8Diag {
771    #[diag(lint_invalid_from_utf8_unchecked)]
772    Unchecked {
773        method: String,
774        valid_up_to: usize,
775        #[label]
776        label: Span,
777    },
778    #[diag(lint_invalid_from_utf8_checked)]
779    Checked {
780        method: String,
781        valid_up_to: usize,
782        #[label]
783        label: Span,
784    },
785}
786
787// reference_casting.rs
788#[derive(LintDiagnostic)]
789pub(crate) enum InvalidReferenceCastingDiag<'tcx> {
790    #[diag(lint_invalid_reference_casting_borrow_as_mut)]
791    #[note(lint_invalid_reference_casting_note_book)]
792    BorrowAsMut {
793        #[label]
794        orig_cast: Option<Span>,
795        #[note(lint_invalid_reference_casting_note_ty_has_interior_mutability)]
796        ty_has_interior_mutability: bool,
797    },
798    #[diag(lint_invalid_reference_casting_assign_to_ref)]
799    #[note(lint_invalid_reference_casting_note_book)]
800    AssignToRef {
801        #[label]
802        orig_cast: Option<Span>,
803        #[note(lint_invalid_reference_casting_note_ty_has_interior_mutability)]
804        ty_has_interior_mutability: bool,
805    },
806    #[diag(lint_invalid_reference_casting_bigger_layout)]
807    #[note(lint_layout)]
808    BiggerLayout {
809        #[label]
810        orig_cast: Option<Span>,
811        #[label(lint_alloc)]
812        alloc: Span,
813        from_ty: Ty<'tcx>,
814        from_size: u64,
815        to_ty: Ty<'tcx>,
816        to_size: u64,
817    },
818}
819
820// hidden_unicode_codepoints.rs
821#[derive(LintDiagnostic)]
822#[diag(lint_hidden_unicode_codepoints)]
823#[note]
824pub(crate) struct HiddenUnicodeCodepointsDiag<'a> {
825    pub label: &'a str,
826    pub count: usize,
827    #[label]
828    pub span_label: Span,
829    #[subdiagnostic]
830    pub labels: Option<HiddenUnicodeCodepointsDiagLabels>,
831    #[subdiagnostic]
832    pub sub: HiddenUnicodeCodepointsDiagSub,
833}
834
835pub(crate) struct HiddenUnicodeCodepointsDiagLabels {
836    pub spans: Vec<(char, Span)>,
837}
838
839impl Subdiagnostic for HiddenUnicodeCodepointsDiagLabels {
840    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
841        for (c, span) in self.spans {
842            diag.span_label(span, format!("{c:?}"));
843        }
844    }
845}
846
847pub(crate) enum HiddenUnicodeCodepointsDiagSub {
848    Escape { spans: Vec<(char, Span)> },
849    NoEscape { spans: Vec<(char, Span)> },
850}
851
852// Used because of multiple multipart_suggestion and note
853impl Subdiagnostic for HiddenUnicodeCodepointsDiagSub {
854    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
855        match self {
856            HiddenUnicodeCodepointsDiagSub::Escape { spans } => {
857                diag.multipart_suggestion_with_style(
858                    fluent::lint_suggestion_remove,
859                    spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
860                    Applicability::MachineApplicable,
861                    SuggestionStyle::HideCodeAlways,
862                );
863                diag.multipart_suggestion(
864                    fluent::lint_suggestion_escape,
865                    spans
866                        .into_iter()
867                        .map(|(c, span)| {
868                            let c = format!("{c:?}");
869                            (span, c[1..c.len() - 1].to_string())
870                        })
871                        .collect(),
872                    Applicability::MachineApplicable,
873                );
874            }
875            HiddenUnicodeCodepointsDiagSub::NoEscape { spans } => {
876                // FIXME: in other suggestions we've reversed the inner spans of doc comments. We
877                // should do the same here to provide the same good suggestions as we do for
878                // literals above.
879                diag.arg(
880                    "escaped",
881                    spans
882                        .into_iter()
883                        .map(|(c, _)| format!("{c:?}"))
884                        .collect::<Vec<String>>()
885                        .join(", "),
886                );
887                diag.note(fluent::lint_suggestion_remove);
888                diag.note(fluent::lint_no_suggestion_note_escape);
889            }
890        }
891    }
892}
893
894// map_unit_fn.rs
895#[derive(LintDiagnostic)]
896#[diag(lint_map_unit_fn)]
897#[note]
898pub(crate) struct MappingToUnit {
899    #[label(lint_function_label)]
900    pub function_label: Span,
901    #[label(lint_argument_label)]
902    pub argument_label: Span,
903    #[label(lint_map_label)]
904    pub map_label: Span,
905    #[suggestion(style = "verbose", code = "for_each", applicability = "maybe-incorrect")]
906    pub suggestion: Span,
907}
908
909// internal.rs
910#[derive(LintDiagnostic)]
911#[diag(lint_default_hash_types)]
912#[note]
913pub(crate) struct DefaultHashTypesDiag<'a> {
914    pub preferred: &'a str,
915    pub used: Symbol,
916}
917
918#[derive(LintDiagnostic)]
919#[diag(lint_query_instability)]
920#[note]
921pub(crate) struct QueryInstability {
922    pub query: Symbol,
923}
924
925#[derive(LintDiagnostic)]
926#[diag(lint_query_untracked)]
927#[note]
928pub(crate) struct QueryUntracked {
929    pub method: Symbol,
930}
931
932#[derive(LintDiagnostic)]
933#[diag(lint_span_use_eq_ctxt)]
934pub(crate) struct SpanUseEqCtxtDiag;
935
936#[derive(LintDiagnostic)]
937#[diag(lint_symbol_intern_string_literal)]
938#[help]
939pub(crate) struct SymbolInternStringLiteralDiag;
940
941#[derive(LintDiagnostic)]
942#[diag(lint_tykind_kind)]
943pub(crate) struct TykindKind {
944    #[suggestion(code = "ty", applicability = "maybe-incorrect")]
945    pub suggestion: Span,
946}
947
948#[derive(LintDiagnostic)]
949#[diag(lint_tykind)]
950#[help]
951pub(crate) struct TykindDiag;
952
953#[derive(LintDiagnostic)]
954#[diag(lint_ty_qualified)]
955pub(crate) struct TyQualified {
956    pub ty: String,
957    #[suggestion(code = "{ty}", applicability = "maybe-incorrect")]
958    pub suggestion: Span,
959}
960
961#[derive(LintDiagnostic)]
962#[diag(lint_type_ir_inherent_usage)]
963#[note]
964pub(crate) struct TypeIrInherentUsage;
965
966#[derive(LintDiagnostic)]
967#[diag(lint_type_ir_trait_usage)]
968#[note]
969pub(crate) struct TypeIrTraitUsage;
970
971#[derive(LintDiagnostic)]
972#[diag(lint_type_ir_direct_use)]
973#[note]
974pub(crate) struct TypeIrDirectUse;
975
976#[derive(LintDiagnostic)]
977#[diag(lint_non_glob_import_type_ir_inherent)]
978pub(crate) struct NonGlobImportTypeIrInherent {
979    #[suggestion(code = "{snippet}", applicability = "maybe-incorrect")]
980    pub suggestion: Option<Span>,
981    pub snippet: &'static str,
982}
983
984#[derive(LintDiagnostic)]
985#[diag(lint_lintpass_by_hand)]
986#[help]
987pub(crate) struct LintPassByHand;
988
989#[derive(LintDiagnostic)]
990#[diag(lint_diag_out_of_impl)]
991pub(crate) struct DiagOutOfImpl;
992
993#[derive(LintDiagnostic)]
994#[diag(lint_untranslatable_diag)]
995pub(crate) struct UntranslatableDiag;
996
997#[derive(LintDiagnostic)]
998#[diag(lint_bad_opt_access)]
999pub(crate) struct BadOptAccessDiag<'a> {
1000    pub msg: &'a str,
1001}
1002
1003// let_underscore.rs
1004#[derive(LintDiagnostic)]
1005pub(crate) enum NonBindingLet {
1006    #[diag(lint_non_binding_let_on_sync_lock)]
1007    SyncLock {
1008        #[label]
1009        pat: Span,
1010        #[subdiagnostic]
1011        sub: NonBindingLetSub,
1012    },
1013    #[diag(lint_non_binding_let_on_drop_type)]
1014    DropType {
1015        #[subdiagnostic]
1016        sub: NonBindingLetSub,
1017    },
1018}
1019
1020pub(crate) struct NonBindingLetSub {
1021    pub suggestion: Span,
1022    pub drop_fn_start_end: Option<(Span, Span)>,
1023    pub is_assign_desugar: bool,
1024}
1025
1026impl Subdiagnostic for NonBindingLetSub {
1027    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
1028        let can_suggest_binding = self.drop_fn_start_end.is_some() || !self.is_assign_desugar;
1029
1030        if can_suggest_binding {
1031            let prefix = if self.is_assign_desugar { "let " } else { "" };
1032            diag.span_suggestion_verbose(
1033                self.suggestion,
1034                fluent::lint_non_binding_let_suggestion,
1035                format!("{prefix}_unused"),
1036                Applicability::MachineApplicable,
1037            );
1038        } else {
1039            diag.span_help(self.suggestion, fluent::lint_non_binding_let_suggestion);
1040        }
1041        if let Some(drop_fn_start_end) = self.drop_fn_start_end {
1042            diag.multipart_suggestion(
1043                fluent::lint_non_binding_let_multi_suggestion,
1044                vec![
1045                    (drop_fn_start_end.0, "drop(".to_string()),
1046                    (drop_fn_start_end.1, ")".to_string()),
1047                ],
1048                Applicability::MachineApplicable,
1049            );
1050        } else {
1051            diag.help(fluent::lint_non_binding_let_multi_drop_fn);
1052        }
1053    }
1054}
1055
1056// levels.rs
1057#[derive(LintDiagnostic)]
1058#[diag(lint_overruled_attribute)]
1059pub(crate) struct OverruledAttributeLint<'a> {
1060    #[label]
1061    pub overruled: Span,
1062    pub lint_level: &'a str,
1063    pub lint_source: Symbol,
1064    #[subdiagnostic]
1065    pub sub: OverruledAttributeSub,
1066}
1067
1068#[derive(LintDiagnostic)]
1069#[diag(lint_deprecated_lint_name)]
1070pub(crate) struct DeprecatedLintName<'a> {
1071    pub name: String,
1072    #[suggestion(code = "{replace}", applicability = "machine-applicable")]
1073    pub suggestion: Span,
1074    pub replace: &'a str,
1075}
1076
1077#[derive(LintDiagnostic)]
1078#[diag(lint_deprecated_lint_name)]
1079#[help]
1080pub(crate) struct DeprecatedLintNameFromCommandLine<'a> {
1081    pub name: String,
1082    pub replace: &'a str,
1083    #[subdiagnostic]
1084    pub requested_level: RequestedLevel<'a>,
1085}
1086
1087#[derive(LintDiagnostic)]
1088#[diag(lint_renamed_lint)]
1089pub(crate) struct RenamedLint<'a> {
1090    pub name: &'a str,
1091    pub replace: &'a str,
1092    #[subdiagnostic]
1093    pub suggestion: RenamedLintSuggestion<'a>,
1094}
1095
1096#[derive(Subdiagnostic)]
1097pub(crate) enum RenamedLintSuggestion<'a> {
1098    #[suggestion(lint_suggestion, code = "{replace}", applicability = "machine-applicable")]
1099    WithSpan {
1100        #[primary_span]
1101        suggestion: Span,
1102        replace: &'a str,
1103    },
1104    #[help(lint_help)]
1105    WithoutSpan { replace: &'a str },
1106}
1107
1108#[derive(LintDiagnostic)]
1109#[diag(lint_renamed_lint)]
1110pub(crate) struct RenamedLintFromCommandLine<'a> {
1111    pub name: &'a str,
1112    pub replace: &'a str,
1113    #[subdiagnostic]
1114    pub suggestion: RenamedLintSuggestion<'a>,
1115    #[subdiagnostic]
1116    pub requested_level: RequestedLevel<'a>,
1117}
1118
1119#[derive(LintDiagnostic)]
1120#[diag(lint_removed_lint)]
1121pub(crate) struct RemovedLint<'a> {
1122    pub name: &'a str,
1123    pub reason: &'a str,
1124}
1125
1126#[derive(LintDiagnostic)]
1127#[diag(lint_removed_lint)]
1128pub(crate) struct RemovedLintFromCommandLine<'a> {
1129    pub name: &'a str,
1130    pub reason: &'a str,
1131    #[subdiagnostic]
1132    pub requested_level: RequestedLevel<'a>,
1133}
1134
1135#[derive(LintDiagnostic)]
1136#[diag(lint_unknown_lint)]
1137pub(crate) struct UnknownLint {
1138    pub name: String,
1139    #[subdiagnostic]
1140    pub suggestion: Option<UnknownLintSuggestion>,
1141}
1142
1143#[derive(Subdiagnostic)]
1144pub(crate) enum UnknownLintSuggestion {
1145    #[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")]
1146    WithSpan {
1147        #[primary_span]
1148        suggestion: Span,
1149        replace: Symbol,
1150        from_rustc: bool,
1151    },
1152    #[help(lint_help)]
1153    WithoutSpan { replace: Symbol, from_rustc: bool },
1154}
1155
1156#[derive(LintDiagnostic)]
1157#[diag(lint_unknown_lint, code = E0602)]
1158pub(crate) struct UnknownLintFromCommandLine<'a> {
1159    pub name: String,
1160    #[subdiagnostic]
1161    pub suggestion: Option<UnknownLintSuggestion>,
1162    #[subdiagnostic]
1163    pub requested_level: RequestedLevel<'a>,
1164}
1165
1166#[derive(LintDiagnostic)]
1167#[diag(lint_ignored_unless_crate_specified)]
1168pub(crate) struct IgnoredUnlessCrateSpecified<'a> {
1169    pub level: &'a str,
1170    pub name: Symbol,
1171}
1172
1173// dangling.rs
1174#[derive(LintDiagnostic)]
1175#[diag(lint_dangling_pointers_from_temporaries)]
1176#[note]
1177#[help(lint_help_bind)]
1178#[help(lint_help_returned)]
1179#[help(lint_help_visit)]
1180// FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts
1181pub(crate) struct DanglingPointersFromTemporaries<'tcx> {
1182    pub callee: Ident,
1183    pub ty: Ty<'tcx>,
1184    #[label(lint_label_ptr)]
1185    pub ptr_span: Span,
1186    #[label(lint_label_temporary)]
1187    pub temporary_span: Span,
1188}
1189
1190#[derive(LintDiagnostic)]
1191#[diag(lint_dangling_pointers_from_locals)]
1192#[note]
1193pub(crate) struct DanglingPointersFromLocals<'tcx> {
1194    pub ret_ty: Ty<'tcx>,
1195    #[label(lint_ret_ty)]
1196    pub ret_ty_span: Span,
1197    pub fn_kind: &'static str,
1198    #[label(lint_local_var)]
1199    pub local_var: Span,
1200    pub local_var_name: Ident,
1201    pub local_var_ty: Ty<'tcx>,
1202    #[label(lint_created_at)]
1203    pub created_at: Option<Span>,
1204}
1205
1206// multiple_supertrait_upcastable.rs
1207#[derive(LintDiagnostic)]
1208#[diag(lint_multiple_supertrait_upcastable)]
1209pub(crate) struct MultipleSupertraitUpcastable {
1210    pub ident: Ident,
1211}
1212
1213// non_ascii_idents.rs
1214#[derive(LintDiagnostic)]
1215#[diag(lint_identifier_non_ascii_char)]
1216pub(crate) struct IdentifierNonAsciiChar;
1217
1218#[derive(LintDiagnostic)]
1219#[diag(lint_identifier_uncommon_codepoints)]
1220#[note]
1221pub(crate) struct IdentifierUncommonCodepoints {
1222    pub codepoints: Vec<char>,
1223    pub codepoints_len: usize,
1224    pub identifier_type: &'static str,
1225}
1226
1227#[derive(LintDiagnostic)]
1228#[diag(lint_confusable_identifier_pair)]
1229pub(crate) struct ConfusableIdentifierPair {
1230    pub existing_sym: Symbol,
1231    pub sym: Symbol,
1232    #[label(lint_other_use)]
1233    pub label: Span,
1234    #[label(lint_current_use)]
1235    pub main_label: Span,
1236}
1237
1238#[derive(LintDiagnostic)]
1239#[diag(lint_mixed_script_confusables)]
1240#[note(lint_includes_note)]
1241#[note]
1242pub(crate) struct MixedScriptConfusables {
1243    pub set: String,
1244    pub includes: String,
1245}
1246
1247// non_fmt_panic.rs
1248pub(crate) struct NonFmtPanicUnused {
1249    pub count: usize,
1250    pub suggestion: Option<Span>,
1251}
1252
1253// Used because of two suggestions based on one Option<Span>
1254impl<'a> LintDiagnostic<'a, ()> for NonFmtPanicUnused {
1255    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
1256        diag.primary_message(fluent::lint_non_fmt_panic_unused);
1257        diag.arg("count", self.count);
1258        diag.note(fluent::lint_note);
1259        if let Some(span) = self.suggestion {
1260            diag.span_suggestion(
1261                span.shrink_to_hi(),
1262                fluent::lint_add_args_suggestion,
1263                ", ...",
1264                Applicability::HasPlaceholders,
1265            );
1266            diag.span_suggestion(
1267                span.shrink_to_lo(),
1268                fluent::lint_add_fmt_suggestion,
1269                "\"{}\", ",
1270                Applicability::MachineApplicable,
1271            );
1272        }
1273    }
1274}
1275
1276#[derive(LintDiagnostic)]
1277#[diag(lint_non_fmt_panic_braces)]
1278#[note]
1279pub(crate) struct NonFmtPanicBraces {
1280    pub count: usize,
1281    #[suggestion(code = "\"{{}}\", ", applicability = "machine-applicable")]
1282    pub suggestion: Option<Span>,
1283}
1284
1285// nonstandard_style.rs
1286#[derive(LintDiagnostic)]
1287#[diag(lint_non_camel_case_type)]
1288pub(crate) struct NonCamelCaseType<'a> {
1289    pub sort: &'a str,
1290    pub name: &'a str,
1291    #[subdiagnostic]
1292    pub sub: NonCamelCaseTypeSub,
1293}
1294
1295#[derive(Subdiagnostic)]
1296pub(crate) enum NonCamelCaseTypeSub {
1297    #[label(lint_label)]
1298    Label {
1299        #[primary_span]
1300        span: Span,
1301    },
1302    #[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")]
1303    Suggestion {
1304        #[primary_span]
1305        span: Span,
1306        replace: String,
1307    },
1308}
1309
1310#[derive(LintDiagnostic)]
1311#[diag(lint_non_snake_case)]
1312pub(crate) struct NonSnakeCaseDiag<'a> {
1313    pub sort: &'a str,
1314    pub name: &'a str,
1315    pub sc: String,
1316    #[subdiagnostic]
1317    pub sub: NonSnakeCaseDiagSub,
1318}
1319
1320pub(crate) enum NonSnakeCaseDiagSub {
1321    Label { span: Span },
1322    Help,
1323    RenameOrConvertSuggestion { span: Span, suggestion: Ident },
1324    ConvertSuggestion { span: Span, suggestion: String },
1325    SuggestionAndNote { span: Span },
1326}
1327
1328impl Subdiagnostic for NonSnakeCaseDiagSub {
1329    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
1330        match self {
1331            NonSnakeCaseDiagSub::Label { span } => {
1332                diag.span_label(span, fluent::lint_label);
1333            }
1334            NonSnakeCaseDiagSub::Help => {
1335                diag.help(fluent::lint_help);
1336            }
1337            NonSnakeCaseDiagSub::ConvertSuggestion { span, suggestion } => {
1338                diag.span_suggestion(
1339                    span,
1340                    fluent::lint_convert_suggestion,
1341                    suggestion,
1342                    Applicability::MaybeIncorrect,
1343                );
1344            }
1345            NonSnakeCaseDiagSub::RenameOrConvertSuggestion { span, suggestion } => {
1346                diag.span_suggestion(
1347                    span,
1348                    fluent::lint_rename_or_convert_suggestion,
1349                    suggestion,
1350                    Applicability::MaybeIncorrect,
1351                );
1352            }
1353            NonSnakeCaseDiagSub::SuggestionAndNote { span } => {
1354                diag.note(fluent::lint_cannot_convert_note);
1355                diag.span_suggestion(
1356                    span,
1357                    fluent::lint_rename_suggestion,
1358                    "",
1359                    Applicability::MaybeIncorrect,
1360                );
1361            }
1362        }
1363    }
1364}
1365
1366#[derive(LintDiagnostic)]
1367#[diag(lint_non_upper_case_global)]
1368pub(crate) struct NonUpperCaseGlobal<'a> {
1369    pub sort: &'a str,
1370    pub name: &'a str,
1371    #[subdiagnostic]
1372    pub sub: NonUpperCaseGlobalSub,
1373    #[subdiagnostic]
1374    pub usages: Vec<NonUpperCaseGlobalSubTool>,
1375}
1376
1377#[derive(Subdiagnostic)]
1378pub(crate) enum NonUpperCaseGlobalSub {
1379    #[label(lint_label)]
1380    Label {
1381        #[primary_span]
1382        span: Span,
1383    },
1384    #[suggestion(lint_suggestion, code = "{replace}")]
1385    Suggestion {
1386        #[primary_span]
1387        span: Span,
1388        #[applicability]
1389        applicability: Applicability,
1390        replace: String,
1391    },
1392}
1393
1394#[derive(Subdiagnostic)]
1395#[suggestion(
1396    lint_suggestion,
1397    code = "{replace}",
1398    applicability = "machine-applicable",
1399    style = "tool-only"
1400)]
1401pub(crate) struct NonUpperCaseGlobalSubTool {
1402    #[primary_span]
1403    pub(crate) span: Span,
1404    pub(crate) replace: String,
1405}
1406
1407// noop_method_call.rs
1408#[derive(LintDiagnostic)]
1409#[diag(lint_noop_method_call)]
1410#[note]
1411pub(crate) struct NoopMethodCallDiag<'a> {
1412    pub method: Ident,
1413    pub orig_ty: Ty<'a>,
1414    pub trait_: Symbol,
1415    #[suggestion(code = "", applicability = "machine-applicable")]
1416    pub label: Span,
1417    #[suggestion(
1418        lint_derive_suggestion,
1419        code = "#[derive(Clone)]\n",
1420        applicability = "maybe-incorrect"
1421    )]
1422    pub suggest_derive: Option<Span>,
1423}
1424
1425#[derive(LintDiagnostic)]
1426#[diag(lint_suspicious_double_ref_deref)]
1427pub(crate) struct SuspiciousDoubleRefDerefDiag<'a> {
1428    pub ty: Ty<'a>,
1429}
1430
1431#[derive(LintDiagnostic)]
1432#[diag(lint_suspicious_double_ref_clone)]
1433pub(crate) struct SuspiciousDoubleRefCloneDiag<'a> {
1434    pub ty: Ty<'a>,
1435}
1436
1437// non_local_defs.rs
1438pub(crate) enum NonLocalDefinitionsDiag {
1439    Impl {
1440        depth: u32,
1441        body_kind_descr: &'static str,
1442        body_name: String,
1443        cargo_update: Option<NonLocalDefinitionsCargoUpdateNote>,
1444        const_anon: Option<Option<Span>>,
1445        doctest: bool,
1446        macro_to_change: Option<(String, &'static str)>,
1447    },
1448    MacroRules {
1449        depth: u32,
1450        body_kind_descr: &'static str,
1451        body_name: String,
1452        doctest: bool,
1453        cargo_update: Option<NonLocalDefinitionsCargoUpdateNote>,
1454    },
1455}
1456
1457impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag {
1458    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
1459        match self {
1460            NonLocalDefinitionsDiag::Impl {
1461                depth,
1462                body_kind_descr,
1463                body_name,
1464                cargo_update,
1465                const_anon,
1466                doctest,
1467                macro_to_change,
1468            } => {
1469                diag.primary_message(fluent::lint_non_local_definitions_impl);
1470                diag.arg("depth", depth);
1471                diag.arg("body_kind_descr", body_kind_descr);
1472                diag.arg("body_name", body_name);
1473
1474                if let Some((macro_to_change, macro_kind)) = macro_to_change {
1475                    diag.arg("macro_to_change", macro_to_change);
1476                    diag.arg("macro_kind", macro_kind);
1477                    diag.note(fluent::lint_macro_to_change);
1478                }
1479                if let Some(cargo_update) = cargo_update {
1480                    diag.subdiagnostic(cargo_update);
1481                }
1482
1483                diag.note(fluent::lint_non_local);
1484
1485                if doctest {
1486                    diag.help(fluent::lint_doctest);
1487                }
1488
1489                if let Some(const_anon) = const_anon {
1490                    diag.note(fluent::lint_exception);
1491                    if let Some(const_anon) = const_anon {
1492                        diag.span_suggestion(
1493                            const_anon,
1494                            fluent::lint_const_anon,
1495                            "_",
1496                            Applicability::MachineApplicable,
1497                        );
1498                    }
1499                }
1500            }
1501            NonLocalDefinitionsDiag::MacroRules {
1502                depth,
1503                body_kind_descr,
1504                body_name,
1505                doctest,
1506                cargo_update,
1507            } => {
1508                diag.primary_message(fluent::lint_non_local_definitions_macro_rules);
1509                diag.arg("depth", depth);
1510                diag.arg("body_kind_descr", body_kind_descr);
1511                diag.arg("body_name", body_name);
1512
1513                if doctest {
1514                    diag.help(fluent::lint_help_doctest);
1515                } else {
1516                    diag.help(fluent::lint_help);
1517                }
1518
1519                diag.note(fluent::lint_non_local);
1520
1521                if let Some(cargo_update) = cargo_update {
1522                    diag.subdiagnostic(cargo_update);
1523                }
1524            }
1525        }
1526    }
1527}
1528
1529#[derive(Subdiagnostic)]
1530#[note(lint_non_local_definitions_cargo_update)]
1531pub(crate) struct NonLocalDefinitionsCargoUpdateNote {
1532    pub macro_kind: &'static str,
1533    pub macro_name: Symbol,
1534    pub crate_name: Symbol,
1535}
1536
1537// precedence.rs
1538#[derive(LintDiagnostic)]
1539#[diag(lint_ambiguous_negative_literals)]
1540#[note(lint_example)]
1541pub(crate) struct AmbiguousNegativeLiteralsDiag {
1542    #[subdiagnostic]
1543    pub negative_literal: AmbiguousNegativeLiteralsNegativeLiteralSuggestion,
1544    #[subdiagnostic]
1545    pub current_behavior: AmbiguousNegativeLiteralsCurrentBehaviorSuggestion,
1546}
1547
1548#[derive(Subdiagnostic)]
1549#[multipart_suggestion(lint_negative_literal, applicability = "maybe-incorrect")]
1550pub(crate) struct AmbiguousNegativeLiteralsNegativeLiteralSuggestion {
1551    #[suggestion_part(code = "(")]
1552    pub start_span: Span,
1553    #[suggestion_part(code = ")")]
1554    pub end_span: Span,
1555}
1556
1557#[derive(Subdiagnostic)]
1558#[multipart_suggestion(lint_current_behavior, applicability = "maybe-incorrect")]
1559pub(crate) struct AmbiguousNegativeLiteralsCurrentBehaviorSuggestion {
1560    #[suggestion_part(code = "(")]
1561    pub start_span: Span,
1562    #[suggestion_part(code = ")")]
1563    pub end_span: Span,
1564}
1565
1566// pass_by_value.rs
1567#[derive(LintDiagnostic)]
1568#[diag(lint_pass_by_value)]
1569pub(crate) struct PassByValueDiag {
1570    pub ty: String,
1571    #[suggestion(code = "{ty}", applicability = "maybe-incorrect")]
1572    pub suggestion: Span,
1573}
1574
1575// redundant_semicolon.rs
1576#[derive(LintDiagnostic)]
1577#[diag(lint_redundant_semicolons)]
1578pub(crate) struct RedundantSemicolonsDiag {
1579    pub multiple: bool,
1580    #[subdiagnostic]
1581    pub suggestion: Option<RedundantSemicolonsSuggestion>,
1582}
1583
1584#[derive(Subdiagnostic)]
1585#[suggestion(lint_redundant_semicolons_suggestion, code = "", applicability = "maybe-incorrect")]
1586pub(crate) struct RedundantSemicolonsSuggestion {
1587    pub multiple_semicolons: bool,
1588    #[primary_span]
1589    pub span: Span,
1590}
1591
1592// traits.rs
1593pub(crate) struct DropTraitConstraintsDiag<'a> {
1594    pub predicate: Clause<'a>,
1595    pub tcx: TyCtxt<'a>,
1596    pub def_id: DefId,
1597}
1598
1599// Needed for def_path_str
1600impl<'a> LintDiagnostic<'a, ()> for DropTraitConstraintsDiag<'_> {
1601    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
1602        diag.primary_message(fluent::lint_drop_trait_constraints);
1603        diag.arg("predicate", self.predicate);
1604        diag.arg("needs_drop", self.tcx.def_path_str(self.def_id));
1605    }
1606}
1607
1608pub(crate) struct DropGlue<'a> {
1609    pub tcx: TyCtxt<'a>,
1610    pub def_id: DefId,
1611}
1612
1613// Needed for def_path_str
1614impl<'a> LintDiagnostic<'a, ()> for DropGlue<'_> {
1615    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
1616        diag.primary_message(fluent::lint_drop_glue);
1617        diag.arg("needs_drop", self.tcx.def_path_str(self.def_id));
1618    }
1619}
1620
1621// types.rs
1622#[derive(LintDiagnostic)]
1623#[diag(lint_range_endpoint_out_of_range)]
1624pub(crate) struct RangeEndpointOutOfRange<'a> {
1625    pub ty: &'a str,
1626    #[subdiagnostic]
1627    pub sub: UseInclusiveRange<'a>,
1628}
1629
1630#[derive(Subdiagnostic)]
1631pub(crate) enum UseInclusiveRange<'a> {
1632    #[suggestion(
1633        lint_range_use_inclusive_range,
1634        code = "{start}..={literal}{suffix}",
1635        applicability = "machine-applicable"
1636    )]
1637    WithoutParen {
1638        #[primary_span]
1639        sugg: Span,
1640        start: String,
1641        literal: u128,
1642        suffix: &'a str,
1643    },
1644    #[multipart_suggestion(lint_range_use_inclusive_range, applicability = "machine-applicable")]
1645    WithParen {
1646        #[suggestion_part(code = "=")]
1647        eq_sugg: Span,
1648        #[suggestion_part(code = "{literal}{suffix}")]
1649        lit_sugg: Span,
1650        literal: u128,
1651        suffix: &'a str,
1652    },
1653}
1654
1655#[derive(LintDiagnostic)]
1656#[diag(lint_overflowing_bin_hex)]
1657pub(crate) struct OverflowingBinHex<'a> {
1658    pub ty: &'a str,
1659    pub lit: String,
1660    pub dec: u128,
1661    pub actually: String,
1662    #[subdiagnostic]
1663    pub sign: OverflowingBinHexSign,
1664    #[subdiagnostic]
1665    pub sub: Option<OverflowingBinHexSub<'a>>,
1666    #[subdiagnostic]
1667    pub sign_bit_sub: Option<OverflowingBinHexSignBitSub<'a>>,
1668}
1669
1670pub(crate) enum OverflowingBinHexSign {
1671    Positive,
1672    Negative,
1673}
1674
1675impl Subdiagnostic for OverflowingBinHexSign {
1676    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
1677        match self {
1678            OverflowingBinHexSign::Positive => {
1679                diag.note(fluent::lint_positive_note);
1680            }
1681            OverflowingBinHexSign::Negative => {
1682                diag.note(fluent::lint_negative_note);
1683                diag.note(fluent::lint_negative_becomes_note);
1684            }
1685        }
1686    }
1687}
1688
1689#[derive(Subdiagnostic)]
1690pub(crate) enum OverflowingBinHexSub<'a> {
1691    #[suggestion(
1692        lint_suggestion,
1693        code = "{sans_suffix}{suggestion_ty}",
1694        applicability = "machine-applicable"
1695    )]
1696    Suggestion {
1697        #[primary_span]
1698        span: Span,
1699        suggestion_ty: &'a str,
1700        sans_suffix: &'a str,
1701    },
1702    #[help(lint_help)]
1703    Help { suggestion_ty: &'a str },
1704}
1705
1706#[derive(Subdiagnostic)]
1707#[suggestion(
1708    lint_sign_bit_suggestion,
1709    code = "{lit_no_suffix}{uint_ty} as {int_ty}",
1710    applicability = "maybe-incorrect"
1711)]
1712pub(crate) struct OverflowingBinHexSignBitSub<'a> {
1713    #[primary_span]
1714    pub span: Span,
1715    pub lit_no_suffix: &'a str,
1716    pub negative_val: String,
1717    pub uint_ty: &'a str,
1718    pub int_ty: &'a str,
1719}
1720
1721#[derive(LintDiagnostic)]
1722#[diag(lint_overflowing_int)]
1723#[note]
1724pub(crate) struct OverflowingInt<'a> {
1725    pub ty: &'a str,
1726    pub lit: String,
1727    pub min: i128,
1728    pub max: u128,
1729    #[subdiagnostic]
1730    pub help: Option<OverflowingIntHelp<'a>>,
1731}
1732
1733#[derive(Subdiagnostic)]
1734#[help(lint_help)]
1735pub(crate) struct OverflowingIntHelp<'a> {
1736    pub suggestion_ty: &'a str,
1737}
1738
1739#[derive(LintDiagnostic)]
1740#[diag(lint_only_cast_u8_to_char)]
1741pub(crate) struct OnlyCastu8ToChar {
1742    #[suggestion(code = "'\\u{{{literal:X}}}'", applicability = "machine-applicable")]
1743    pub span: Span,
1744    pub literal: u128,
1745}
1746
1747#[derive(LintDiagnostic)]
1748#[diag(lint_overflowing_uint)]
1749#[note]
1750pub(crate) struct OverflowingUInt<'a> {
1751    pub ty: &'a str,
1752    pub lit: String,
1753    pub min: u128,
1754    pub max: u128,
1755}
1756
1757#[derive(LintDiagnostic)]
1758#[diag(lint_overflowing_literal)]
1759#[note]
1760pub(crate) struct OverflowingLiteral<'a> {
1761    pub ty: &'a str,
1762    pub lit: String,
1763}
1764
1765#[derive(LintDiagnostic)]
1766#[diag(lint_surrogate_char_cast)]
1767#[note]
1768pub(crate) struct SurrogateCharCast {
1769    pub literal: u128,
1770}
1771
1772#[derive(LintDiagnostic)]
1773#[diag(lint_too_large_char_cast)]
1774#[note]
1775pub(crate) struct TooLargeCharCast {
1776    pub literal: u128,
1777}
1778
1779#[derive(LintDiagnostic)]
1780#[diag(lint_uses_power_alignment)]
1781pub(crate) struct UsesPowerAlignment;
1782
1783#[derive(LintDiagnostic)]
1784#[diag(lint_unused_comparisons)]
1785pub(crate) struct UnusedComparisons;
1786
1787#[derive(LintDiagnostic)]
1788pub(crate) enum InvalidNanComparisons {
1789    #[diag(lint_invalid_nan_comparisons_eq_ne)]
1790    EqNe {
1791        #[subdiagnostic]
1792        suggestion: InvalidNanComparisonsSuggestion,
1793    },
1794    #[diag(lint_invalid_nan_comparisons_lt_le_gt_ge)]
1795    LtLeGtGe,
1796}
1797
1798#[derive(Subdiagnostic)]
1799pub(crate) enum InvalidNanComparisonsSuggestion {
1800    #[multipart_suggestion(
1801        lint_suggestion,
1802        style = "verbose",
1803        applicability = "machine-applicable"
1804    )]
1805    Spanful {
1806        #[suggestion_part(code = "!")]
1807        neg: Option<Span>,
1808        #[suggestion_part(code = ".is_nan()")]
1809        float: Span,
1810        #[suggestion_part(code = "")]
1811        nan_plus_binop: Span,
1812    },
1813    #[help(lint_suggestion)]
1814    Spanless,
1815}
1816
1817#[derive(LintDiagnostic)]
1818pub(crate) enum AmbiguousWidePointerComparisons<'a> {
1819    #[diag(lint_ambiguous_wide_pointer_comparisons)]
1820    SpanfulEq {
1821        #[subdiagnostic]
1822        addr_suggestion: AmbiguousWidePointerComparisonsAddrSuggestion<'a>,
1823        #[subdiagnostic]
1824        addr_metadata_suggestion: Option<AmbiguousWidePointerComparisonsAddrMetadataSuggestion<'a>>,
1825    },
1826    #[diag(lint_ambiguous_wide_pointer_comparisons)]
1827    SpanfulCmp {
1828        #[subdiagnostic]
1829        cast_suggestion: AmbiguousWidePointerComparisonsCastSuggestion<'a>,
1830        #[subdiagnostic]
1831        expect_suggestion: AmbiguousWidePointerComparisonsExpectSuggestion<'a>,
1832    },
1833    #[diag(lint_ambiguous_wide_pointer_comparisons)]
1834    #[help(lint_addr_metadata_suggestion)]
1835    #[help(lint_addr_suggestion)]
1836    Spanless,
1837}
1838
1839#[derive(Subdiagnostic)]
1840#[multipart_suggestion(
1841    lint_addr_metadata_suggestion,
1842    style = "verbose",
1843    // FIXME(#53934): make machine-applicable again
1844    applicability = "maybe-incorrect"
1845)]
1846pub(crate) struct AmbiguousWidePointerComparisonsAddrMetadataSuggestion<'a> {
1847    pub ne: &'a str,
1848    pub deref_left: &'a str,
1849    pub deref_right: &'a str,
1850    pub l_modifiers: &'a str,
1851    pub r_modifiers: &'a str,
1852    #[suggestion_part(code = "{ne}std::ptr::eq({deref_left}")]
1853    pub left: Span,
1854    #[suggestion_part(code = "{l_modifiers}, {deref_right}")]
1855    pub middle: Span,
1856    #[suggestion_part(code = "{r_modifiers})")]
1857    pub right: Span,
1858}
1859
1860#[derive(Subdiagnostic)]
1861#[multipart_suggestion(
1862    lint_addr_suggestion,
1863    style = "verbose",
1864    // FIXME(#53934): make machine-applicable again
1865    applicability = "maybe-incorrect"
1866)]
1867pub(crate) struct AmbiguousWidePointerComparisonsAddrSuggestion<'a> {
1868    pub(crate) ne: &'a str,
1869    pub(crate) deref_left: &'a str,
1870    pub(crate) deref_right: &'a str,
1871    pub(crate) l_modifiers: &'a str,
1872    pub(crate) r_modifiers: &'a str,
1873    #[suggestion_part(code = "{ne}std::ptr::addr_eq({deref_left}")]
1874    pub(crate) left: Span,
1875    #[suggestion_part(code = "{l_modifiers}, {deref_right}")]
1876    pub(crate) middle: Span,
1877    #[suggestion_part(code = "{r_modifiers})")]
1878    pub(crate) right: Span,
1879}
1880
1881#[derive(Subdiagnostic)]
1882#[multipart_suggestion(
1883    lint_cast_suggestion,
1884    style = "verbose",
1885    // FIXME(#53934): make machine-applicable again
1886    applicability = "maybe-incorrect"
1887)]
1888pub(crate) struct AmbiguousWidePointerComparisonsCastSuggestion<'a> {
1889    pub(crate) deref_left: &'a str,
1890    pub(crate) deref_right: &'a str,
1891    pub(crate) paren_left: &'a str,
1892    pub(crate) paren_right: &'a str,
1893    pub(crate) l_modifiers: &'a str,
1894    pub(crate) r_modifiers: &'a str,
1895    #[suggestion_part(code = "({deref_left}")]
1896    pub(crate) left_before: Option<Span>,
1897    #[suggestion_part(code = "{l_modifiers}{paren_left}.cast::<()>()")]
1898    pub(crate) left_after: Span,
1899    #[suggestion_part(code = "({deref_right}")]
1900    pub(crate) right_before: Option<Span>,
1901    #[suggestion_part(code = "{r_modifiers}{paren_right}.cast::<()>()")]
1902    pub(crate) right_after: Span,
1903}
1904
1905#[derive(Subdiagnostic)]
1906#[multipart_suggestion(
1907    lint_expect_suggestion,
1908    style = "verbose",
1909    // FIXME(#53934): make machine-applicable again
1910    applicability = "maybe-incorrect"
1911)]
1912pub(crate) struct AmbiguousWidePointerComparisonsExpectSuggestion<'a> {
1913    pub(crate) paren_left: &'a str,
1914    pub(crate) paren_right: &'a str,
1915    // FIXME(#127436): Adjust once resolved
1916    #[suggestion_part(
1917        code = r#"{{ #[expect(ambiguous_wide_pointer_comparisons, reason = "...")] {paren_left}"#
1918    )]
1919    pub(crate) before: Span,
1920    #[suggestion_part(code = "{paren_right} }}")]
1921    pub(crate) after: Span,
1922}
1923
1924#[derive(LintDiagnostic)]
1925pub(crate) enum UnpredictableFunctionPointerComparisons<'a, 'tcx> {
1926    #[diag(lint_unpredictable_fn_pointer_comparisons)]
1927    #[note(lint_note_duplicated_fn)]
1928    #[note(lint_note_deduplicated_fn)]
1929    #[note(lint_note_visit_fn_addr_eq)]
1930    Suggestion {
1931        #[subdiagnostic]
1932        sugg: UnpredictableFunctionPointerComparisonsSuggestion<'a, 'tcx>,
1933    },
1934    #[diag(lint_unpredictable_fn_pointer_comparisons)]
1935    #[note(lint_note_duplicated_fn)]
1936    #[note(lint_note_deduplicated_fn)]
1937    #[note(lint_note_visit_fn_addr_eq)]
1938    Warn,
1939}
1940
1941#[derive(Subdiagnostic)]
1942pub(crate) enum UnpredictableFunctionPointerComparisonsSuggestion<'a, 'tcx> {
1943    #[multipart_suggestion(
1944        lint_fn_addr_eq_suggestion,
1945        style = "verbose",
1946        applicability = "maybe-incorrect"
1947    )]
1948    FnAddrEq {
1949        ne: &'a str,
1950        deref_left: &'a str,
1951        deref_right: &'a str,
1952        #[suggestion_part(code = "{ne}std::ptr::fn_addr_eq({deref_left}")]
1953        left: Span,
1954        #[suggestion_part(code = ", {deref_right}")]
1955        middle: Span,
1956        #[suggestion_part(code = ")")]
1957        right: Span,
1958    },
1959    #[multipart_suggestion(
1960        lint_fn_addr_eq_suggestion,
1961        style = "verbose",
1962        applicability = "maybe-incorrect"
1963    )]
1964    FnAddrEqWithCast {
1965        ne: &'a str,
1966        deref_left: &'a str,
1967        deref_right: &'a str,
1968        fn_sig: rustc_middle::ty::PolyFnSig<'tcx>,
1969        #[suggestion_part(code = "{ne}std::ptr::fn_addr_eq({deref_left}")]
1970        left: Span,
1971        #[suggestion_part(code = ", {deref_right}")]
1972        middle: Span,
1973        #[suggestion_part(code = " as {fn_sig})")]
1974        right: Span,
1975    },
1976}
1977
1978pub(crate) struct ImproperCTypes<'a> {
1979    pub ty: Ty<'a>,
1980    pub desc: &'a str,
1981    pub label: Span,
1982    pub help: Option<DiagMessage>,
1983    pub note: DiagMessage,
1984    pub span_note: Option<Span>,
1985}
1986
1987// Used because of the complexity of Option<DiagMessage>, DiagMessage, and Option<Span>
1988impl<'a> LintDiagnostic<'a, ()> for ImproperCTypes<'_> {
1989    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
1990        diag.primary_message(fluent::lint_improper_ctypes);
1991        diag.arg("ty", self.ty);
1992        diag.arg("desc", self.desc);
1993        diag.span_label(self.label, fluent::lint_label);
1994        if let Some(help) = self.help {
1995            diag.help(help);
1996        }
1997        diag.note(self.note);
1998        if let Some(note) = self.span_note {
1999            diag.span_note(note, fluent::lint_note);
2000        }
2001    }
2002}
2003
2004#[derive(LintDiagnostic)]
2005#[diag(lint_variant_size_differences)]
2006pub(crate) struct VariantSizeDifferencesDiag {
2007    pub largest: u64,
2008}
2009
2010#[derive(LintDiagnostic)]
2011#[diag(lint_atomic_ordering_load)]
2012#[help]
2013pub(crate) struct AtomicOrderingLoad;
2014
2015#[derive(LintDiagnostic)]
2016#[diag(lint_atomic_ordering_store)]
2017#[help]
2018pub(crate) struct AtomicOrderingStore;
2019
2020#[derive(LintDiagnostic)]
2021#[diag(lint_atomic_ordering_fence)]
2022#[help]
2023pub(crate) struct AtomicOrderingFence;
2024
2025#[derive(LintDiagnostic)]
2026#[diag(lint_atomic_ordering_invalid)]
2027#[help]
2028pub(crate) struct InvalidAtomicOrderingDiag {
2029    pub method: Symbol,
2030    #[label]
2031    pub fail_order_arg_span: Span,
2032}
2033
2034// unused.rs
2035#[derive(LintDiagnostic)]
2036#[diag(lint_unused_op)]
2037pub(crate) struct UnusedOp<'a> {
2038    pub op: &'a str,
2039    #[label]
2040    pub label: Span,
2041    #[subdiagnostic]
2042    pub suggestion: UnusedOpSuggestion,
2043}
2044
2045#[derive(Subdiagnostic)]
2046pub(crate) enum UnusedOpSuggestion {
2047    #[suggestion(
2048        lint_suggestion,
2049        style = "verbose",
2050        code = "let _ = ",
2051        applicability = "maybe-incorrect"
2052    )]
2053    NormalExpr {
2054        #[primary_span]
2055        span: Span,
2056    },
2057    #[multipart_suggestion(lint_suggestion, style = "verbose", applicability = "maybe-incorrect")]
2058    BlockTailExpr {
2059        #[suggestion_part(code = "let _ = ")]
2060        before_span: Span,
2061        #[suggestion_part(code = ";")]
2062        after_span: Span,
2063    },
2064}
2065
2066#[derive(LintDiagnostic)]
2067#[diag(lint_unused_result)]
2068pub(crate) struct UnusedResult<'a> {
2069    pub ty: Ty<'a>,
2070}
2071
2072// FIXME(davidtwco): this isn't properly translatable because of the
2073// pre/post strings
2074#[derive(LintDiagnostic)]
2075#[diag(lint_unused_closure)]
2076#[note]
2077pub(crate) struct UnusedClosure<'a> {
2078    pub count: usize,
2079    pub pre: &'a str,
2080    pub post: &'a str,
2081}
2082
2083// FIXME(davidtwco): this isn't properly translatable because of the
2084// pre/post strings
2085#[derive(LintDiagnostic)]
2086#[diag(lint_unused_coroutine)]
2087#[note]
2088pub(crate) struct UnusedCoroutine<'a> {
2089    pub count: usize,
2090    pub pre: &'a str,
2091    pub post: &'a str,
2092}
2093
2094// FIXME(davidtwco): this isn't properly translatable because of the pre/post
2095// strings
2096pub(crate) struct UnusedDef<'a, 'b> {
2097    pub pre: &'a str,
2098    pub post: &'a str,
2099    pub cx: &'a LateContext<'b>,
2100    pub def_id: DefId,
2101    pub note: Option<Symbol>,
2102    pub suggestion: Option<UnusedDefSuggestion>,
2103}
2104
2105#[derive(Subdiagnostic)]
2106
2107pub(crate) enum UnusedDefSuggestion {
2108    #[suggestion(
2109        lint_suggestion,
2110        style = "verbose",
2111        code = "let _ = ",
2112        applicability = "maybe-incorrect"
2113    )]
2114    NormalExpr {
2115        #[primary_span]
2116        span: Span,
2117    },
2118    #[multipart_suggestion(lint_suggestion, style = "verbose", applicability = "maybe-incorrect")]
2119    BlockTailExpr {
2120        #[suggestion_part(code = "let _ = ")]
2121        before_span: Span,
2122        #[suggestion_part(code = ";")]
2123        after_span: Span,
2124    },
2125}
2126
2127// Needed because of def_path_str
2128impl<'a> LintDiagnostic<'a, ()> for UnusedDef<'_, '_> {
2129    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
2130        diag.primary_message(fluent::lint_unused_def);
2131        diag.arg("pre", self.pre);
2132        diag.arg("post", self.post);
2133        diag.arg("def", self.cx.tcx.def_path_str(self.def_id));
2134        // check for #[must_use = "..."]
2135        if let Some(note) = self.note {
2136            diag.note(note.to_string());
2137        }
2138        if let Some(sugg) = self.suggestion {
2139            diag.subdiagnostic(sugg);
2140        }
2141    }
2142}
2143
2144#[derive(LintDiagnostic)]
2145#[diag(lint_path_statement_drop)]
2146pub(crate) struct PathStatementDrop {
2147    #[subdiagnostic]
2148    pub sub: PathStatementDropSub,
2149}
2150
2151#[derive(Subdiagnostic)]
2152pub(crate) enum PathStatementDropSub {
2153    #[suggestion(lint_suggestion, code = "drop({snippet});", applicability = "machine-applicable")]
2154    Suggestion {
2155        #[primary_span]
2156        span: Span,
2157        snippet: String,
2158    },
2159    #[help(lint_help)]
2160    Help {
2161        #[primary_span]
2162        span: Span,
2163    },
2164}
2165
2166#[derive(LintDiagnostic)]
2167#[diag(lint_path_statement_no_effect)]
2168pub(crate) struct PathStatementNoEffect;
2169
2170#[derive(LintDiagnostic)]
2171#[diag(lint_unused_delim)]
2172pub(crate) struct UnusedDelim<'a> {
2173    pub delim: &'static str,
2174    pub item: &'a str,
2175    #[subdiagnostic]
2176    pub suggestion: Option<UnusedDelimSuggestion>,
2177}
2178
2179#[derive(Subdiagnostic)]
2180#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable")]
2181pub(crate) struct UnusedDelimSuggestion {
2182    #[suggestion_part(code = "{start_replace}")]
2183    pub start_span: Span,
2184    pub start_replace: &'static str,
2185    #[suggestion_part(code = "{end_replace}")]
2186    pub end_span: Span,
2187    pub end_replace: &'static str,
2188}
2189
2190#[derive(LintDiagnostic)]
2191#[diag(lint_unused_import_braces)]
2192pub(crate) struct UnusedImportBracesDiag {
2193    pub node: Symbol,
2194}
2195
2196#[derive(LintDiagnostic)]
2197#[diag(lint_unused_allocation)]
2198pub(crate) struct UnusedAllocationDiag;
2199
2200#[derive(LintDiagnostic)]
2201#[diag(lint_unused_allocation_mut)]
2202pub(crate) struct UnusedAllocationMutDiag;
2203
2204pub(crate) struct AsyncFnInTraitDiag {
2205    pub sugg: Option<Vec<(Span, String)>>,
2206}
2207
2208impl<'a> LintDiagnostic<'a, ()> for AsyncFnInTraitDiag {
2209    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
2210        diag.primary_message(fluent::lint_async_fn_in_trait);
2211        diag.note(fluent::lint_note);
2212        if let Some(sugg) = self.sugg {
2213            diag.multipart_suggestion(fluent::lint_suggestion, sugg, Applicability::MaybeIncorrect);
2214        }
2215    }
2216}
2217
2218#[derive(LintDiagnostic)]
2219#[diag(lint_unit_bindings)]
2220pub(crate) struct UnitBindingsDiag {
2221    #[label]
2222    pub label: Span,
2223}
2224
2225#[derive(LintDiagnostic)]
2226pub(crate) enum InvalidAsmLabel {
2227    #[diag(lint_invalid_asm_label_named)]
2228    #[help]
2229    #[note]
2230    Named {
2231        #[note(lint_invalid_asm_label_no_span)]
2232        missing_precise_span: bool,
2233    },
2234    #[diag(lint_invalid_asm_label_format_arg)]
2235    #[help]
2236    #[note(lint_note1)]
2237    #[note(lint_note2)]
2238    FormatArg {
2239        #[note(lint_invalid_asm_label_no_span)]
2240        missing_precise_span: bool,
2241    },
2242    #[diag(lint_invalid_asm_label_binary)]
2243    #[help]
2244    #[note(lint_note1)]
2245    #[note(lint_note2)]
2246    Binary {
2247        #[note(lint_invalid_asm_label_no_span)]
2248        missing_precise_span: bool,
2249        // hack to get a label on the whole span, must match the emitted span
2250        #[label]
2251        span: Span,
2252    },
2253}
2254
2255#[derive(Subdiagnostic)]
2256pub(crate) enum UnexpectedCfgCargoHelp {
2257    #[help(lint_unexpected_cfg_add_cargo_feature)]
2258    #[help(lint_unexpected_cfg_add_cargo_toml_lint_cfg)]
2259    LintCfg { cargo_toml_lint_cfg: String },
2260    #[help(lint_unexpected_cfg_add_cargo_feature)]
2261    #[help(lint_unexpected_cfg_add_cargo_toml_lint_cfg)]
2262    #[help(lint_unexpected_cfg_add_build_rs_println)]
2263    LintCfgAndBuildRs { cargo_toml_lint_cfg: String, build_rs_println: String },
2264}
2265
2266impl UnexpectedCfgCargoHelp {
2267    fn cargo_toml_lint_cfg(unescaped: &str) -> String {
2268        format!(
2269            "\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{unescaped}'] }}"
2270        )
2271    }
2272
2273    pub(crate) fn lint_cfg(unescaped: &str) -> Self {
2274        UnexpectedCfgCargoHelp::LintCfg {
2275            cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped),
2276        }
2277    }
2278
2279    pub(crate) fn lint_cfg_and_build_rs(unescaped: &str, escaped: &str) -> Self {
2280        UnexpectedCfgCargoHelp::LintCfgAndBuildRs {
2281            cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped),
2282            build_rs_println: format!("println!(\"cargo::rustc-check-cfg={escaped}\");"),
2283        }
2284    }
2285}
2286
2287#[derive(Subdiagnostic)]
2288#[help(lint_unexpected_cfg_add_cmdline_arg)]
2289pub(crate) struct UnexpectedCfgRustcHelp {
2290    pub cmdline_arg: String,
2291}
2292
2293impl UnexpectedCfgRustcHelp {
2294    pub(crate) fn new(unescaped: &str) -> Self {
2295        Self { cmdline_arg: format!("--check-cfg={unescaped}") }
2296    }
2297}
2298
2299#[derive(Subdiagnostic)]
2300#[note(lint_unexpected_cfg_from_external_macro_origin)]
2301#[help(lint_unexpected_cfg_from_external_macro_refer)]
2302pub(crate) struct UnexpectedCfgRustcMacroHelp {
2303    pub macro_kind: &'static str,
2304    pub macro_name: Symbol,
2305}
2306
2307#[derive(Subdiagnostic)]
2308#[note(lint_unexpected_cfg_from_external_macro_origin)]
2309#[help(lint_unexpected_cfg_from_external_macro_refer)]
2310#[help(lint_unexpected_cfg_cargo_update)]
2311pub(crate) struct UnexpectedCfgCargoMacroHelp {
2312    pub macro_kind: &'static str,
2313    pub macro_name: Symbol,
2314    pub crate_name: Symbol,
2315}
2316
2317#[derive(LintDiagnostic)]
2318#[diag(lint_unexpected_cfg_name)]
2319pub(crate) struct UnexpectedCfgName {
2320    #[subdiagnostic]
2321    pub code_sugg: unexpected_cfg_name::CodeSuggestion,
2322    #[subdiagnostic]
2323    pub invocation_help: unexpected_cfg_name::InvocationHelp,
2324
2325    pub name: Symbol,
2326}
2327
2328pub(crate) mod unexpected_cfg_name {
2329    use rustc_errors::DiagSymbolList;
2330    use rustc_macros::Subdiagnostic;
2331    use rustc_span::{Ident, Span, Symbol};
2332
2333    #[derive(Subdiagnostic)]
2334    pub(crate) enum CodeSuggestion {
2335        #[help(lint_unexpected_cfg_define_features)]
2336        DefineFeatures,
2337        #[multipart_suggestion(
2338            lint_unexpected_cfg_name_version_syntax,
2339            applicability = "machine-applicable"
2340        )]
2341        VersionSyntax {
2342            #[suggestion_part(code = "(")]
2343            between_name_and_value: Span,
2344            #[suggestion_part(code = ")")]
2345            after_value: Span,
2346        },
2347        #[suggestion(
2348            lint_unexpected_cfg_name_similar_name_value,
2349            applicability = "maybe-incorrect",
2350            code = "{code}"
2351        )]
2352        SimilarNameAndValue {
2353            #[primary_span]
2354            span: Span,
2355            code: String,
2356        },
2357        #[suggestion(
2358            lint_unexpected_cfg_name_similar_name_no_value,
2359            applicability = "maybe-incorrect",
2360            code = "{code}"
2361        )]
2362        SimilarNameNoValue {
2363            #[primary_span]
2364            span: Span,
2365            code: String,
2366        },
2367        #[suggestion(
2368            lint_unexpected_cfg_name_similar_name_different_values,
2369            applicability = "maybe-incorrect",
2370            code = "{code}"
2371        )]
2372        SimilarNameDifferentValues {
2373            #[primary_span]
2374            span: Span,
2375            code: String,
2376            #[subdiagnostic]
2377            expected: Option<ExpectedValues>,
2378        },
2379        #[suggestion(
2380            lint_unexpected_cfg_name_similar_name,
2381            applicability = "maybe-incorrect",
2382            code = "{code}"
2383        )]
2384        SimilarName {
2385            #[primary_span]
2386            span: Span,
2387            code: String,
2388            #[subdiagnostic]
2389            expected: Option<ExpectedValues>,
2390        },
2391        SimilarValues {
2392            #[subdiagnostic]
2393            with_similar_values: Vec<FoundWithSimilarValue>,
2394            #[subdiagnostic]
2395            expected_names: Option<ExpectedNames>,
2396        },
2397    }
2398
2399    #[derive(Subdiagnostic)]
2400    #[help(lint_unexpected_cfg_name_expected_values)]
2401    pub(crate) struct ExpectedValues {
2402        pub best_match: Symbol,
2403        pub possibilities: DiagSymbolList,
2404    }
2405
2406    #[derive(Subdiagnostic)]
2407    #[suggestion(
2408        lint_unexpected_cfg_name_with_similar_value,
2409        applicability = "maybe-incorrect",
2410        code = "{code}"
2411    )]
2412    pub(crate) struct FoundWithSimilarValue {
2413        #[primary_span]
2414        pub span: Span,
2415        pub code: String,
2416    }
2417
2418    #[derive(Subdiagnostic)]
2419    #[help_once(lint_unexpected_cfg_name_expected_names)]
2420    pub(crate) struct ExpectedNames {
2421        pub possibilities: DiagSymbolList<Ident>,
2422        pub and_more: usize,
2423    }
2424
2425    #[derive(Subdiagnostic)]
2426    pub(crate) enum InvocationHelp {
2427        #[note(lint_unexpected_cfg_doc_cargo)]
2428        Cargo {
2429            #[subdiagnostic]
2430            macro_help: Option<super::UnexpectedCfgCargoMacroHelp>,
2431            #[subdiagnostic]
2432            help: Option<super::UnexpectedCfgCargoHelp>,
2433        },
2434        #[note(lint_unexpected_cfg_doc_rustc)]
2435        Rustc {
2436            #[subdiagnostic]
2437            macro_help: Option<super::UnexpectedCfgRustcMacroHelp>,
2438            #[subdiagnostic]
2439            help: super::UnexpectedCfgRustcHelp,
2440        },
2441    }
2442}
2443
2444#[derive(LintDiagnostic)]
2445#[diag(lint_unexpected_cfg_value)]
2446pub(crate) struct UnexpectedCfgValue {
2447    #[subdiagnostic]
2448    pub code_sugg: unexpected_cfg_value::CodeSuggestion,
2449    #[subdiagnostic]
2450    pub invocation_help: unexpected_cfg_value::InvocationHelp,
2451
2452    pub has_value: bool,
2453    pub value: String,
2454}
2455
2456pub(crate) mod unexpected_cfg_value {
2457    use rustc_errors::DiagSymbolList;
2458    use rustc_macros::Subdiagnostic;
2459    use rustc_span::{Span, Symbol};
2460
2461    #[derive(Subdiagnostic)]
2462    pub(crate) enum CodeSuggestion {
2463        ChangeValue {
2464            #[subdiagnostic]
2465            expected_values: ExpectedValues,
2466            #[subdiagnostic]
2467            suggestion: Option<ChangeValueSuggestion>,
2468        },
2469        #[note(lint_unexpected_cfg_value_no_expected_value)]
2470        RemoveValue {
2471            #[subdiagnostic]
2472            suggestion: Option<RemoveValueSuggestion>,
2473
2474            name: Symbol,
2475        },
2476        #[note(lint_unexpected_cfg_value_no_expected_values)]
2477        RemoveCondition {
2478            #[subdiagnostic]
2479            suggestion: RemoveConditionSuggestion,
2480
2481            name: Symbol,
2482        },
2483    }
2484
2485    #[derive(Subdiagnostic)]
2486    pub(crate) enum ChangeValueSuggestion {
2487        #[suggestion(
2488            lint_unexpected_cfg_value_similar_name,
2489            code = r#""{best_match}""#,
2490            applicability = "maybe-incorrect"
2491        )]
2492        SimilarName {
2493            #[primary_span]
2494            span: Span,
2495            best_match: Symbol,
2496        },
2497        #[suggestion(
2498            lint_unexpected_cfg_value_specify_value,
2499            code = r#" = "{first_possibility}""#,
2500            applicability = "maybe-incorrect"
2501        )]
2502        SpecifyValue {
2503            #[primary_span]
2504            span: Span,
2505            first_possibility: Symbol,
2506        },
2507    }
2508
2509    #[derive(Subdiagnostic)]
2510    #[suggestion(
2511        lint_unexpected_cfg_value_remove_value,
2512        code = "",
2513        applicability = "maybe-incorrect"
2514    )]
2515    pub(crate) struct RemoveValueSuggestion {
2516        #[primary_span]
2517        pub span: Span,
2518    }
2519
2520    #[derive(Subdiagnostic)]
2521    #[suggestion(
2522        lint_unexpected_cfg_value_remove_condition,
2523        code = "",
2524        applicability = "maybe-incorrect"
2525    )]
2526    pub(crate) struct RemoveConditionSuggestion {
2527        #[primary_span]
2528        pub span: Span,
2529    }
2530
2531    #[derive(Subdiagnostic)]
2532    #[note(lint_unexpected_cfg_value_expected_values)]
2533    pub(crate) struct ExpectedValues {
2534        pub name: Symbol,
2535        pub have_none_possibility: bool,
2536        pub possibilities: DiagSymbolList,
2537        pub and_more: usize,
2538    }
2539
2540    #[derive(Subdiagnostic)]
2541    pub(crate) enum InvocationHelp {
2542        #[note(lint_unexpected_cfg_doc_cargo)]
2543        Cargo {
2544            #[subdiagnostic]
2545            help: Option<CargoHelp>,
2546            #[subdiagnostic]
2547            macro_help: Option<super::UnexpectedCfgCargoMacroHelp>,
2548        },
2549        #[note(lint_unexpected_cfg_doc_rustc)]
2550        Rustc {
2551            #[subdiagnostic]
2552            help: Option<super::UnexpectedCfgRustcHelp>,
2553            #[subdiagnostic]
2554            macro_help: Option<super::UnexpectedCfgRustcMacroHelp>,
2555        },
2556    }
2557
2558    #[derive(Subdiagnostic)]
2559    pub(crate) enum CargoHelp {
2560        #[help(lint_unexpected_cfg_value_add_feature)]
2561        AddFeature {
2562            value: Symbol,
2563        },
2564        #[help(lint_unexpected_cfg_define_features)]
2565        DefineFeatures,
2566        Other(#[subdiagnostic] super::UnexpectedCfgCargoHelp),
2567    }
2568}
2569
2570#[derive(LintDiagnostic)]
2571#[diag(lint_unexpected_builtin_cfg)]
2572#[note(lint_controlled_by)]
2573#[note(lint_incoherent)]
2574pub(crate) struct UnexpectedBuiltinCfg {
2575    pub(crate) cfg: String,
2576    pub(crate) cfg_name: Symbol,
2577    pub(crate) controlled_by: &'static str,
2578}
2579
2580#[derive(LintDiagnostic)]
2581#[diag(lint_macro_use_deprecated)]
2582#[help]
2583pub(crate) struct MacroUseDeprecated;
2584
2585#[derive(LintDiagnostic)]
2586#[diag(lint_unused_macro_use)]
2587pub(crate) struct UnusedMacroUse;
2588
2589#[derive(LintDiagnostic)]
2590#[diag(lint_private_extern_crate_reexport, code = E0365)]
2591pub(crate) struct PrivateExternCrateReexport {
2592    pub ident: Ident,
2593    #[suggestion(code = "pub ", style = "verbose", applicability = "maybe-incorrect")]
2594    pub sugg: Span,
2595}
2596
2597#[derive(LintDiagnostic)]
2598#[diag(lint_unused_label)]
2599pub(crate) struct UnusedLabel;
2600
2601#[derive(LintDiagnostic)]
2602#[diag(lint_macro_is_private)]
2603pub(crate) struct MacroIsPrivate {
2604    pub ident: Ident,
2605}
2606
2607#[derive(LintDiagnostic)]
2608#[diag(lint_unused_macro_definition)]
2609pub(crate) struct UnusedMacroDefinition {
2610    pub name: Symbol,
2611}
2612
2613#[derive(LintDiagnostic)]
2614#[diag(lint_macro_rule_never_used)]
2615pub(crate) struct MacroRuleNeverUsed {
2616    pub n: usize,
2617    pub name: Symbol,
2618}
2619
2620pub(crate) struct UnstableFeature {
2621    pub msg: DiagMessage,
2622}
2623
2624impl<'a> LintDiagnostic<'a, ()> for UnstableFeature {
2625    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
2626        diag.primary_message(self.msg);
2627    }
2628}
2629
2630#[derive(LintDiagnostic)]
2631#[diag(lint_avoid_intel_syntax)]
2632pub(crate) struct AvoidIntelSyntax;
2633
2634#[derive(LintDiagnostic)]
2635#[diag(lint_avoid_att_syntax)]
2636pub(crate) struct AvoidAttSyntax;
2637
2638#[derive(LintDiagnostic)]
2639#[diag(lint_incomplete_include)]
2640pub(crate) struct IncompleteInclude;
2641
2642#[derive(LintDiagnostic)]
2643#[diag(lint_unnameable_test_items)]
2644pub(crate) struct UnnameableTestItems;
2645
2646#[derive(LintDiagnostic)]
2647#[diag(lint_duplicate_macro_attribute)]
2648pub(crate) struct DuplicateMacroAttribute;
2649
2650#[derive(LintDiagnostic)]
2651#[diag(lint_cfg_attr_no_attributes)]
2652pub(crate) struct CfgAttrNoAttributes;
2653
2654#[derive(LintDiagnostic)]
2655#[diag(lint_metavariable_still_repeating)]
2656pub(crate) struct MetaVariableStillRepeating {
2657    pub name: MacroRulesNormalizedIdent,
2658}
2659
2660#[derive(LintDiagnostic)]
2661#[diag(lint_metavariable_wrong_operator)]
2662pub(crate) struct MetaVariableWrongOperator;
2663
2664#[derive(LintDiagnostic)]
2665#[diag(lint_duplicate_matcher_binding)]
2666pub(crate) struct DuplicateMatcherBinding;
2667
2668#[derive(LintDiagnostic)]
2669#[diag(lint_unknown_macro_variable)]
2670pub(crate) struct UnknownMacroVariable {
2671    pub name: MacroRulesNormalizedIdent,
2672}
2673
2674#[derive(LintDiagnostic)]
2675#[diag(lint_unused_crate_dependency)]
2676#[help]
2677pub(crate) struct UnusedCrateDependency {
2678    pub extern_crate: Symbol,
2679    pub local_crate: Symbol,
2680}
2681
2682// FIXME(jdonszelmann): duplicated in rustc_attr_parsing, should be moved there completely.
2683#[derive(LintDiagnostic)]
2684#[diag(lint_ill_formed_attribute_input)]
2685pub(crate) struct IllFormedAttributeInput {
2686    pub num_suggestions: usize,
2687    pub suggestions: DiagArgValue,
2688    #[note]
2689    pub has_docs: bool,
2690    pub docs: &'static str,
2691}
2692
2693#[derive(LintDiagnostic)]
2694pub(crate) enum InnerAttributeUnstable {
2695    #[diag(lint_inner_macro_attribute_unstable)]
2696    InnerMacroAttribute,
2697    #[diag(lint_custom_inner_attribute_unstable)]
2698    CustomInnerAttribute,
2699}
2700
2701#[derive(LintDiagnostic)]
2702#[diag(lint_unknown_diagnostic_attribute)]
2703pub(crate) struct UnknownDiagnosticAttribute {
2704    #[subdiagnostic]
2705    pub typo: Option<UnknownDiagnosticAttributeTypoSugg>,
2706}
2707
2708#[derive(Subdiagnostic)]
2709#[suggestion(
2710    lint_unknown_diagnostic_attribute_typo_sugg,
2711    style = "verbose",
2712    code = "{typo_name}",
2713    applicability = "machine-applicable"
2714)]
2715pub(crate) struct UnknownDiagnosticAttributeTypoSugg {
2716    #[primary_span]
2717    pub span: Span,
2718    pub typo_name: Symbol,
2719}
2720
2721#[derive(LintDiagnostic)]
2722#[diag(lint_unicode_text_flow)]
2723#[note]
2724pub(crate) struct UnicodeTextFlow {
2725    #[label]
2726    pub comment_span: Span,
2727    #[subdiagnostic]
2728    pub characters: Vec<UnicodeCharNoteSub>,
2729    #[subdiagnostic]
2730    pub suggestions: Option<UnicodeTextFlowSuggestion>,
2731
2732    pub num_codepoints: usize,
2733}
2734
2735#[derive(Subdiagnostic)]
2736#[label(lint_label_comment_char)]
2737pub(crate) struct UnicodeCharNoteSub {
2738    #[primary_span]
2739    pub span: Span,
2740    pub c_debug: String,
2741}
2742
2743#[derive(Subdiagnostic)]
2744#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable", style = "hidden")]
2745pub(crate) struct UnicodeTextFlowSuggestion {
2746    #[suggestion_part(code = "")]
2747    pub spans: Vec<Span>,
2748}
2749
2750#[derive(LintDiagnostic)]
2751#[diag(lint_abs_path_with_module)]
2752pub(crate) struct AbsPathWithModule {
2753    #[subdiagnostic]
2754    pub sugg: AbsPathWithModuleSugg,
2755}
2756
2757#[derive(Subdiagnostic)]
2758#[suggestion(lint_suggestion, code = "{replacement}")]
2759pub(crate) struct AbsPathWithModuleSugg {
2760    #[primary_span]
2761    pub span: Span,
2762    #[applicability]
2763    pub applicability: Applicability,
2764    pub replacement: String,
2765}
2766
2767#[derive(LintDiagnostic)]
2768#[diag(lint_proc_macro_derive_resolution_fallback)]
2769pub(crate) struct ProcMacroDeriveResolutionFallback {
2770    #[label]
2771    pub span: Span,
2772    pub ns: Namespace,
2773    pub ident: Ident,
2774}
2775
2776#[derive(LintDiagnostic)]
2777#[diag(lint_macro_expanded_macro_exports_accessed_by_absolute_paths)]
2778pub(crate) struct MacroExpandedMacroExportsAccessedByAbsolutePaths {
2779    #[note]
2780    pub definition: Span,
2781}
2782
2783#[derive(LintDiagnostic)]
2784#[diag(lint_hidden_lifetime_parameters)]
2785pub(crate) struct ElidedLifetimesInPaths {
2786    #[subdiagnostic]
2787    pub subdiag: ElidedLifetimeInPathSubdiag,
2788}
2789
2790#[derive(LintDiagnostic)]
2791#[diag(lint_invalid_crate_type_value)]
2792pub(crate) struct UnknownCrateTypes {
2793    #[subdiagnostic]
2794    pub sugg: Option<UnknownCrateTypesSub>,
2795}
2796
2797#[derive(Subdiagnostic)]
2798#[suggestion(lint_suggestion, code = r#""{candidate}""#, applicability = "maybe-incorrect")]
2799pub(crate) struct UnknownCrateTypesSub {
2800    #[primary_span]
2801    pub span: Span,
2802    pub candidate: Symbol,
2803}
2804
2805#[derive(LintDiagnostic)]
2806#[diag(lint_unused_imports)]
2807pub(crate) struct UnusedImports {
2808    #[subdiagnostic]
2809    pub sugg: UnusedImportsSugg,
2810    #[help]
2811    pub test_module_span: Option<Span>,
2812
2813    pub span_snippets: DiagArgValue,
2814    pub num_snippets: usize,
2815}
2816
2817#[derive(Subdiagnostic)]
2818pub(crate) enum UnusedImportsSugg {
2819    #[suggestion(
2820        lint_suggestion_remove_whole_use,
2821        applicability = "machine-applicable",
2822        code = "",
2823        style = "tool-only"
2824    )]
2825    RemoveWholeUse {
2826        #[primary_span]
2827        span: Span,
2828    },
2829    #[multipart_suggestion(
2830        lint_suggestion_remove_imports,
2831        applicability = "machine-applicable",
2832        style = "tool-only"
2833    )]
2834    RemoveImports {
2835        #[suggestion_part(code = "")]
2836        remove_spans: Vec<Span>,
2837        num_to_remove: usize,
2838    },
2839}
2840
2841#[derive(LintDiagnostic)]
2842#[diag(lint_redundant_import)]
2843pub(crate) struct RedundantImport {
2844    #[subdiagnostic]
2845    pub subs: Vec<RedundantImportSub>,
2846
2847    pub ident: Ident,
2848}
2849
2850#[derive(Subdiagnostic)]
2851pub(crate) enum RedundantImportSub {
2852    #[label(lint_label_imported_here)]
2853    ImportedHere(#[primary_span] Span),
2854    #[label(lint_label_defined_here)]
2855    DefinedHere(#[primary_span] Span),
2856    #[label(lint_label_imported_prelude)]
2857    ImportedPrelude(#[primary_span] Span),
2858    #[label(lint_label_defined_prelude)]
2859    DefinedPrelude(#[primary_span] Span),
2860}
2861
2862#[derive(LintDiagnostic)]
2863#[diag(lint_unused_doc_comment)]
2864#[help]
2865pub(crate) struct UnusedDocComment {
2866    #[label]
2867    pub span: Span,
2868}
2869
2870#[derive(LintDiagnostic)]
2871pub(crate) enum PatternsInFnsWithoutBody {
2872    #[diag(lint_pattern_in_foreign)]
2873    Foreign {
2874        #[subdiagnostic]
2875        sub: PatternsInFnsWithoutBodySub,
2876    },
2877    #[diag(lint_pattern_in_bodiless)]
2878    Bodiless {
2879        #[subdiagnostic]
2880        sub: PatternsInFnsWithoutBodySub,
2881    },
2882}
2883
2884#[derive(Subdiagnostic)]
2885#[suggestion(lint_remove_mut_from_pattern, code = "{ident}", applicability = "machine-applicable")]
2886pub(crate) struct PatternsInFnsWithoutBodySub {
2887    #[primary_span]
2888    pub span: Span,
2889
2890    pub ident: Ident,
2891}
2892
2893#[derive(LintDiagnostic)]
2894#[diag(lint_extern_without_abi)]
2895pub(crate) struct MissingAbi {
2896    #[suggestion(code = "extern {default_abi}", applicability = "machine-applicable")]
2897    pub span: Span,
2898    pub default_abi: ExternAbi,
2899}
2900
2901#[derive(LintDiagnostic)]
2902#[diag(lint_legacy_derive_helpers)]
2903pub(crate) struct LegacyDeriveHelpers {
2904    #[label]
2905    pub span: Span,
2906}
2907
2908#[derive(LintDiagnostic)]
2909#[diag(lint_or_patterns_back_compat)]
2910pub(crate) struct OrPatternsBackCompat {
2911    #[suggestion(code = "{suggestion}", applicability = "machine-applicable")]
2912    pub span: Span,
2913    pub suggestion: String,
2914}
2915
2916#[derive(LintDiagnostic)]
2917#[diag(lint_reserved_prefix)]
2918pub(crate) struct ReservedPrefix {
2919    #[label]
2920    pub label: Span,
2921    #[suggestion(code = " ", applicability = "machine-applicable")]
2922    pub suggestion: Span,
2923
2924    pub prefix: String,
2925}
2926
2927#[derive(LintDiagnostic)]
2928#[diag(lint_raw_prefix)]
2929pub(crate) struct RawPrefix {
2930    #[label]
2931    pub label: Span,
2932    #[suggestion(code = " ", applicability = "machine-applicable")]
2933    pub suggestion: Span,
2934}
2935
2936#[derive(LintDiagnostic)]
2937#[diag(lint_unused_builtin_attribute)]
2938pub(crate) struct UnusedBuiltinAttribute {
2939    #[note]
2940    pub invoc_span: Span,
2941    pub attr_name: Symbol,
2942    pub macro_name: String,
2943    #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
2944    pub attr_span: Span,
2945}
2946
2947#[derive(LintDiagnostic)]
2948#[diag(lint_trailing_semi_macro)]
2949pub(crate) struct TrailingMacro {
2950    #[note(lint_note1)]
2951    #[note(lint_note2)]
2952    pub is_trailing: bool,
2953
2954    pub name: Ident,
2955}
2956
2957#[derive(LintDiagnostic)]
2958#[diag(lint_break_with_label_and_loop)]
2959pub(crate) struct BreakWithLabelAndLoop {
2960    #[subdiagnostic]
2961    pub sub: BreakWithLabelAndLoopSub,
2962}
2963
2964#[derive(Subdiagnostic)]
2965#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable")]
2966pub(crate) struct BreakWithLabelAndLoopSub {
2967    #[suggestion_part(code = "(")]
2968    pub left: Span,
2969    #[suggestion_part(code = ")")]
2970    pub right: Span,
2971}
2972
2973#[derive(LintDiagnostic)]
2974#[diag(lint_deprecated_where_clause_location)]
2975#[note]
2976pub(crate) struct DeprecatedWhereClauseLocation {
2977    #[subdiagnostic]
2978    pub suggestion: DeprecatedWhereClauseLocationSugg,
2979}
2980
2981#[derive(Subdiagnostic)]
2982pub(crate) enum DeprecatedWhereClauseLocationSugg {
2983    #[multipart_suggestion(lint_suggestion_move_to_end, applicability = "machine-applicable")]
2984    MoveToEnd {
2985        #[suggestion_part(code = "")]
2986        left: Span,
2987        #[suggestion_part(code = "{sugg}")]
2988        right: Span,
2989
2990        sugg: String,
2991    },
2992    #[suggestion(lint_suggestion_remove_where, code = "", applicability = "machine-applicable")]
2993    RemoveWhere {
2994        #[primary_span]
2995        span: Span,
2996    },
2997}
2998
2999#[derive(LintDiagnostic)]
3000#[diag(lint_missing_unsafe_on_extern)]
3001pub(crate) struct MissingUnsafeOnExtern {
3002    #[suggestion(code = "unsafe ", applicability = "machine-applicable")]
3003    pub suggestion: Span,
3004}
3005
3006#[derive(LintDiagnostic)]
3007#[diag(lint_single_use_lifetime)]
3008pub(crate) struct SingleUseLifetime {
3009    #[label(lint_label_param)]
3010    pub param_span: Span,
3011    #[label(lint_label_use)]
3012    pub use_span: Span,
3013    #[subdiagnostic]
3014    pub suggestion: Option<SingleUseLifetimeSugg>,
3015
3016    pub ident: Ident,
3017}
3018
3019#[derive(Subdiagnostic)]
3020#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable")]
3021pub(crate) struct SingleUseLifetimeSugg {
3022    #[suggestion_part(code = "")]
3023    pub deletion_span: Option<Span>,
3024    #[suggestion_part(code = "{replace_lt}")]
3025    pub use_span: Span,
3026
3027    pub replace_lt: String,
3028}
3029
3030#[derive(LintDiagnostic)]
3031#[diag(lint_unused_lifetime)]
3032pub(crate) struct UnusedLifetime {
3033    #[suggestion(code = "", applicability = "machine-applicable")]
3034    pub deletion_span: Option<Span>,
3035
3036    pub ident: Ident,
3037}
3038
3039#[derive(LintDiagnostic)]
3040#[diag(lint_named_argument_used_positionally)]
3041pub(crate) struct NamedArgumentUsedPositionally {
3042    #[label(lint_label_named_arg)]
3043    pub named_arg_sp: Span,
3044    #[label(lint_label_position_arg)]
3045    pub position_label_sp: Option<Span>,
3046    #[suggestion(style = "verbose", code = "{name}", applicability = "maybe-incorrect")]
3047    pub suggestion: Option<Span>,
3048
3049    pub name: String,
3050    pub named_arg_name: String,
3051}
3052
3053#[derive(LintDiagnostic)]
3054#[diag(lint_byte_slice_in_packed_struct_with_derive)]
3055#[help]
3056pub(crate) struct ByteSliceInPackedStructWithDerive {
3057    // FIXME: make this translatable
3058    pub ty: String,
3059}
3060
3061#[derive(LintDiagnostic)]
3062#[diag(lint_unused_extern_crate)]
3063pub(crate) struct UnusedExternCrate {
3064    #[label]
3065    pub span: Span,
3066    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
3067    pub removal_span: Span,
3068}
3069
3070#[derive(LintDiagnostic)]
3071#[diag(lint_extern_crate_not_idiomatic)]
3072pub(crate) struct ExternCrateNotIdiomatic {
3073    #[suggestion(style = "verbose", code = "{code}", applicability = "machine-applicable")]
3074    pub span: Span,
3075
3076    pub code: &'static str,
3077}
3078
3079// FIXME: make this translatable
3080pub(crate) struct AmbiguousGlobImports {
3081    pub ambiguity: AmbiguityErrorDiag,
3082}
3083
3084impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for AmbiguousGlobImports {
3085    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) {
3086        diag.primary_message(self.ambiguity.msg.clone());
3087        rustc_errors::report_ambiguity_error(diag, self.ambiguity);
3088    }
3089}
3090
3091#[derive(LintDiagnostic)]
3092#[diag(lint_ambiguous_glob_reexport)]
3093pub(crate) struct AmbiguousGlobReexports {
3094    #[label(lint_label_first_reexport)]
3095    pub first_reexport: Span,
3096    #[label(lint_label_duplicate_reexport)]
3097    pub duplicate_reexport: Span,
3098
3099    pub name: String,
3100    // FIXME: make this translatable
3101    pub namespace: String,
3102}
3103
3104#[derive(LintDiagnostic)]
3105#[diag(lint_hidden_glob_reexport)]
3106pub(crate) struct HiddenGlobReexports {
3107    #[note(lint_note_glob_reexport)]
3108    pub glob_reexport: Span,
3109    #[note(lint_note_private_item)]
3110    pub private_item: Span,
3111
3112    pub name: String,
3113    // FIXME: make this translatable
3114    pub namespace: String,
3115}
3116
3117#[derive(LintDiagnostic)]
3118#[diag(lint_reexport_private_dependency)]
3119pub(crate) struct ReexportPrivateDependency {
3120    pub name: String,
3121    pub kind: String,
3122    pub krate: Symbol,
3123}
3124
3125#[derive(LintDiagnostic)]
3126#[diag(lint_unnecessary_qualification)]
3127pub(crate) struct UnusedQualifications {
3128    #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
3129    pub removal_span: Span,
3130}
3131
3132#[derive(LintDiagnostic)]
3133#[diag(lint_associated_const_elided_lifetime)]
3134pub(crate) struct AssociatedConstElidedLifetime {
3135    #[suggestion(style = "verbose", code = "{code}", applicability = "machine-applicable")]
3136    pub span: Span,
3137
3138    pub code: &'static str,
3139    pub elided: bool,
3140    #[note]
3141    pub lifetimes_in_scope: MultiSpan,
3142}
3143
3144#[derive(LintDiagnostic)]
3145#[diag(lint_redundant_import_visibility)]
3146pub(crate) struct RedundantImportVisibility {
3147    #[note]
3148    pub span: Span,
3149    #[help]
3150    pub help: (),
3151
3152    pub import_vis: String,
3153    pub max_vis: String,
3154}
3155
3156#[derive(LintDiagnostic)]
3157#[diag(lint_unsafe_attr_outside_unsafe)]
3158pub(crate) struct UnsafeAttrOutsideUnsafe {
3159    #[label]
3160    pub span: Span,
3161    #[subdiagnostic]
3162    pub suggestion: UnsafeAttrOutsideUnsafeSuggestion,
3163}
3164
3165#[derive(Subdiagnostic)]
3166#[multipart_suggestion(
3167    lint_unsafe_attr_outside_unsafe_suggestion,
3168    applicability = "machine-applicable"
3169)]
3170pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion {
3171    #[suggestion_part(code = "unsafe(")]
3172    pub left: Span,
3173    #[suggestion_part(code = ")")]
3174    pub right: Span,
3175}
3176
3177#[derive(LintDiagnostic)]
3178#[diag(lint_out_of_scope_macro_calls)]
3179#[help]
3180pub(crate) struct OutOfScopeMacroCalls {
3181    #[label]
3182    pub span: Span,
3183    pub path: String,
3184    pub location: String,
3185}
3186
3187#[derive(LintDiagnostic)]
3188#[diag(lint_static_mut_refs_lint)]
3189pub(crate) struct RefOfMutStatic<'a> {
3190    #[label]
3191    pub span: Span,
3192    #[subdiagnostic]
3193    pub sugg: Option<MutRefSugg>,
3194    pub shared_label: &'a str,
3195    #[note(lint_shared_note)]
3196    pub shared_note: bool,
3197    #[note(lint_mut_note)]
3198    pub mut_note: bool,
3199}
3200
3201#[derive(Subdiagnostic)]
3202pub(crate) enum MutRefSugg {
3203    #[multipart_suggestion(lint_suggestion, style = "verbose", applicability = "maybe-incorrect")]
3204    Shared {
3205        #[suggestion_part(code = "&raw const ")]
3206        span: Span,
3207    },
3208    #[multipart_suggestion(
3209        lint_suggestion_mut,
3210        style = "verbose",
3211        applicability = "maybe-incorrect"
3212    )]
3213    Mut {
3214        #[suggestion_part(code = "&raw mut ")]
3215        span: Span,
3216    },
3217}
3218
3219#[derive(LintDiagnostic)]
3220#[diag(lint_unqualified_local_imports)]
3221pub(crate) struct UnqualifiedLocalImportsDiag {}
3222
3223#[derive(LintDiagnostic)]
3224#[diag(lint_reserved_string)]
3225pub(crate) struct ReservedString {
3226    #[suggestion(code = " ", applicability = "machine-applicable")]
3227    pub suggestion: Span,
3228}
3229
3230#[derive(LintDiagnostic)]
3231#[diag(lint_reserved_multihash)]
3232pub(crate) struct ReservedMultihash {
3233    #[suggestion(code = " ", applicability = "machine-applicable")]
3234    pub suggestion: Span,
3235}
3236
3237#[derive(Debug)]
3238pub(crate) struct MismatchedLifetimeSyntaxes {
3239    pub inputs: LifetimeSyntaxCategories<Vec<Span>>,
3240    pub outputs: LifetimeSyntaxCategories<Vec<Span>>,
3241
3242    pub suggestions: Vec<MismatchedLifetimeSyntaxesSuggestion>,
3243}
3244
3245impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for MismatchedLifetimeSyntaxes {
3246    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) {
3247        let counts = self.inputs.len() + self.outputs.len();
3248        let message = match counts {
3249            LifetimeSyntaxCategories { hidden: 0, elided: 0, named: 0 } => {
3250                panic!("No lifetime mismatch detected")
3251            }
3252
3253            LifetimeSyntaxCategories { hidden: _, elided: _, named: 0 } => {
3254                fluent::lint_mismatched_lifetime_syntaxes_hiding_while_elided
3255            }
3256
3257            LifetimeSyntaxCategories { hidden: _, elided: 0, named: _ } => {
3258                fluent::lint_mismatched_lifetime_syntaxes_hiding_while_named
3259            }
3260
3261            LifetimeSyntaxCategories { hidden: 0, elided: _, named: _ } => {
3262                fluent::lint_mismatched_lifetime_syntaxes_eliding_while_named
3263            }
3264
3265            LifetimeSyntaxCategories { hidden: _, elided: _, named: _ } => {
3266                fluent::lint_mismatched_lifetime_syntaxes_hiding_and_eliding_while_named
3267            }
3268        };
3269        diag.primary_message(message);
3270
3271        for s in self.inputs.hidden {
3272            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_hidden);
3273        }
3274        for s in self.inputs.elided {
3275            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_elided);
3276        }
3277        for s in self.inputs.named {
3278            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_named);
3279        }
3280
3281        for s in self.outputs.hidden {
3282            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_hidden);
3283        }
3284        for s in self.outputs.elided {
3285            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_elided);
3286        }
3287        for s in self.outputs.named {
3288            diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_named);
3289        }
3290
3291        diag.help(fluent::lint_mismatched_lifetime_syntaxes_help);
3292
3293        let mut suggestions = self.suggestions.into_iter();
3294        if let Some(s) = suggestions.next() {
3295            diag.subdiagnostic(s);
3296
3297            for mut s in suggestions {
3298                s.make_optional_alternative();
3299                diag.subdiagnostic(s);
3300            }
3301        }
3302    }
3303}
3304
3305#[derive(Debug)]
3306pub(crate) enum MismatchedLifetimeSyntaxesSuggestion {
3307    Implicit {
3308        suggestions: Vec<Span>,
3309        optional_alternative: bool,
3310    },
3311
3312    Mixed {
3313        implicit_suggestions: Vec<Span>,
3314        explicit_anonymous_suggestions: Vec<(Span, String)>,
3315        optional_alternative: bool,
3316    },
3317
3318    Explicit {
3319        lifetime_name: String,
3320        suggestions: Vec<(Span, String)>,
3321        optional_alternative: bool,
3322    },
3323}
3324
3325impl MismatchedLifetimeSyntaxesSuggestion {
3326    fn make_optional_alternative(&mut self) {
3327        use MismatchedLifetimeSyntaxesSuggestion::*;
3328
3329        let optional_alternative = match self {
3330            Implicit { optional_alternative, .. }
3331            | Mixed { optional_alternative, .. }
3332            | Explicit { optional_alternative, .. } => optional_alternative,
3333        };
3334
3335        *optional_alternative = true;
3336    }
3337}
3338
3339impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
3340    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
3341        use MismatchedLifetimeSyntaxesSuggestion::*;
3342
3343        let style = |optional_alternative| {
3344            if optional_alternative {
3345                SuggestionStyle::CompletelyHidden
3346            } else {
3347                SuggestionStyle::ShowAlways
3348            }
3349        };
3350
3351        let applicability = |optional_alternative| {
3352            // `cargo fix` can't handle more than one fix for the same issue,
3353            // so hide alternative suggestions from it by marking them as maybe-incorrect
3354            if optional_alternative {
3355                Applicability::MaybeIncorrect
3356            } else {
3357                Applicability::MachineApplicable
3358            }
3359        };
3360
3361        match self {
3362            Implicit { suggestions, optional_alternative } => {
3363                let suggestions = suggestions.into_iter().map(|s| (s, String::new())).collect();
3364                diag.multipart_suggestion_with_style(
3365                    fluent::lint_mismatched_lifetime_syntaxes_suggestion_implicit,
3366                    suggestions,
3367                    applicability(optional_alternative),
3368                    style(optional_alternative),
3369                );
3370            }
3371
3372            Mixed {
3373                implicit_suggestions,
3374                explicit_anonymous_suggestions,
3375                optional_alternative,
3376            } => {
3377                let message = if implicit_suggestions.is_empty() {
3378                    fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths
3379                } else {
3380                    fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed
3381                };
3382
3383                let implicit_suggestions =
3384                    implicit_suggestions.into_iter().map(|s| (s, String::new()));
3385
3386                let suggestions =
3387                    implicit_suggestions.chain(explicit_anonymous_suggestions).collect();
3388
3389                diag.multipart_suggestion_with_style(
3390                    message,
3391                    suggestions,
3392                    applicability(optional_alternative),
3393                    style(optional_alternative),
3394                );
3395            }
3396
3397            Explicit { lifetime_name, suggestions, optional_alternative } => {
3398                diag.arg("lifetime_name", lifetime_name);
3399                let msg = diag.eagerly_translate(
3400                    fluent::lint_mismatched_lifetime_syntaxes_suggestion_explicit,
3401                );
3402                diag.remove_arg("lifetime_name");
3403                diag.multipart_suggestion_with_style(
3404                    msg,
3405                    suggestions,
3406                    applicability(optional_alternative),
3407                    style(optional_alternative),
3408                );
3409            }
3410        }
3411    }
3412}