1#![allow(internal_features)]
7#![allow(rustc::diagnostic_outside_of_impl)]
8#![allow(rustc::direct_use_of_rustc_type_ir)]
9#![allow(rustc::untranslatable_diagnostic)]
10#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
11#![doc(rust_logo)]
12#![feature(array_windows)]
13#![feature(assert_matches)]
14#![feature(associated_type_defaults)]
15#![feature(box_patterns)]
16#![feature(default_field_values)]
17#![feature(error_reporter)]
18#![feature(negative_impls)]
19#![feature(never_type)]
20#![feature(rustc_attrs)]
21#![feature(rustdoc_internals)]
22#![feature(try_blocks)]
23#![feature(yeet_expr)]
24extern crate self as rustc_errors;
27
28use std::assert_matches::assert_matches;
29use std::backtrace::{Backtrace, BacktraceStatus};
30use std::borrow::Cow;
31use std::cell::Cell;
32use std::error::Report;
33use std::ffi::OsStr;
34use std::hash::Hash;
35use std::io::Write;
36use std::num::NonZero;
37use std::ops::DerefMut;
38use std::path::{Path, PathBuf};
39use std::{fmt, panic};
40
41use Level::*;
42pub use anstream::{AutoStream, ColorChoice};
45pub use anstyle::{
46    Ansi256Color, AnsiColor, Color, EffectIter, Effects, Reset, RgbColor, Style as Anstyle,
47};
48pub use codes::*;
49pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
50pub use diagnostic::{
51    BugAbort, Diag, DiagArgMap, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee,
52    FatalAbort, LintDiagnostic, LintDiagnosticBox, StringPart, Subdiag, Subdiagnostic,
53};
54pub use diagnostic_impls::{
55    DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
56    IndicateAnonymousLifetime, SingleLabelManySpans,
57};
58pub use emitter::ColorConfig;
59use emitter::{ConfusionType, DynEmitter, Emitter, detect_confusion_type, is_different};
60use rustc_data_structures::AtomicRef;
61use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
62use rustc_data_structures::stable_hasher::StableHasher;
63use rustc_data_structures::sync::{DynSend, Lock};
64pub use rustc_error_messages::{
65    DiagArg, DiagArgFromDisplay, DiagArgName, DiagArgValue, DiagMessage, FluentBundle, IntoDiagArg,
66    LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage,
67    fallback_fluent_bundle, fluent_bundle, into_diag_arg_using_display,
68};
69use rustc_hashes::Hash128;
70pub use rustc_lint_defs::{Applicability, listify, pluralize};
71use rustc_lint_defs::{Lint, LintExpectationId};
72use rustc_macros::{Decodable, Encodable};
73pub use rustc_span::ErrorGuaranteed;
74pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
75use rustc_span::source_map::SourceMap;
76use rustc_span::{BytePos, DUMMY_SP, Loc, Span};
77pub use snippet::Style;
78use tracing::debug;
79
80use crate::emitter::TimingEvent;
81use crate::registry::Registry;
82use crate::timings::TimingRecord;
83
84pub mod annotate_snippet_emitter_writer;
85pub mod codes;
86mod decorate_diag;
87mod diagnostic;
88mod diagnostic_impls;
89pub mod emitter;
90pub mod error;
91pub mod json;
92mod lock;
93pub mod markdown;
94pub mod registry;
95mod snippet;
96mod styled_buffer;
97#[cfg(test)]
98mod tests;
99pub mod timings;
100pub mod translation;
101
102pub type PResult<'a, T> = Result<T, Diag<'a>>;
103
104rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
105
106#[cfg(target_pointer_width = "64")]
108rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24);
109#[cfg(target_pointer_width = "64")]
110rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24);
111
112pub trait LintEmitter: Copy {
115    type Id: Copy;
116    #[track_caller]
117    fn emit_node_span_lint(
118        self,
119        lint: &'static Lint,
120        hir_id: Self::Id,
121        span: impl Into<MultiSpan>,
122        decorator: impl for<'a> LintDiagnostic<'a, ()> + DynSend + 'static,
123    );
124}
125
126#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
127pub enum SuggestionStyle {
128    HideCodeInline,
130    HideCodeAlways,
132    CompletelyHidden,
134    ShowCode,
138    ShowAlways,
140}
141
142impl SuggestionStyle {
143    fn hide_inline(&self) -> bool {
144        !matches!(*self, SuggestionStyle::ShowCode)
145    }
146}
147
148#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
150pub enum Suggestions {
151    Enabled(Vec<CodeSuggestion>),
156    Sealed(Box<[CodeSuggestion]>),
160    Disabled,
164}
165
166impl Suggestions {
167    pub fn unwrap_tag(self) -> Vec<CodeSuggestion> {
169        match self {
170            Suggestions::Enabled(suggestions) => suggestions,
171            Suggestions::Sealed(suggestions) => suggestions.into_vec(),
172            Suggestions::Disabled => Vec::new(),
173        }
174    }
175}
176
177impl Default for Suggestions {
178    fn default() -> Self {
179        Self::Enabled(vec![])
180    }
181}
182
183#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
184pub struct CodeSuggestion {
185    pub substitutions: Vec<Substitution>,
207    pub msg: DiagMessage,
208    pub style: SuggestionStyle,
210    pub applicability: Applicability,
216}
217
218#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
219pub struct Substitution {
221    pub parts: Vec<SubstitutionPart>,
222}
223
224#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
225pub struct SubstitutionPart {
226    pub span: Span,
227    pub snippet: String,
228}
229
230#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
231pub struct TrimmedSubstitutionPart {
232    pub original_span: Span,
233    pub span: Span,
234    pub snippet: String,
235}
236
237#[derive(Debug, Clone, Copy)]
240pub(crate) struct SubstitutionHighlight {
241    start: usize,
242    end: usize,
243}
244
245impl SubstitutionPart {
246    fn trim_trivial_replacements(self, sm: &SourceMap) -> TrimmedSubstitutionPart {
249        let mut trimmed_part = TrimmedSubstitutionPart {
250            original_span: self.span,
251            span: self.span,
252            snippet: self.snippet,
253        };
254        if trimmed_part.snippet.is_empty() {
255            return trimmed_part;
256        }
257        let Ok(snippet) = sm.span_to_snippet(trimmed_part.span) else {
258            return trimmed_part;
259        };
260
261        if let Some((prefix, substr, suffix)) = as_substr(&snippet, &trimmed_part.snippet) {
262            trimmed_part.span = Span::new(
263                trimmed_part.span.lo() + BytePos(prefix as u32),
264                trimmed_part.span.hi() - BytePos(suffix as u32),
265                trimmed_part.span.ctxt(),
266                trimmed_part.span.parent(),
267            );
268            trimmed_part.snippet = substr.to_string();
269        }
270        trimmed_part
271    }
272}
273
274impl TrimmedSubstitutionPart {
275    pub fn is_addition(&self, sm: &SourceMap) -> bool {
276        !self.snippet.is_empty() && !self.replaces_meaningful_content(sm)
277    }
278
279    pub fn is_deletion(&self, sm: &SourceMap) -> bool {
280        self.snippet.trim().is_empty() && self.replaces_meaningful_content(sm)
281    }
282
283    pub fn is_replacement(&self, sm: &SourceMap) -> bool {
284        !self.snippet.is_empty() && self.replaces_meaningful_content(sm)
285    }
286
287    pub fn is_destructive_replacement(&self, sm: &SourceMap) -> bool {
292        self.is_replacement(sm)
293            && !sm
294                .span_to_snippet(self.span)
295                .is_ok_and(|snippet| as_substr(snippet.trim(), self.snippet.trim()).is_some())
296    }
297
298    fn replaces_meaningful_content(&self, sm: &SourceMap) -> bool {
299        sm.span_to_snippet(self.span)
300            .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty())
301    }
302}
303
304fn as_substr<'a>(original: &'a str, suggestion: &'a str) -> Option<(usize, &'a str, usize)> {
309    let common_prefix = original
310        .chars()
311        .zip(suggestion.chars())
312        .take_while(|(c1, c2)| c1 == c2)
313        .map(|(c, _)| c.len_utf8())
314        .sum();
315    let original = &original[common_prefix..];
316    let suggestion = &suggestion[common_prefix..];
317    if suggestion.ends_with(original) {
318        let common_suffix = original.len();
319        Some((common_prefix, &suggestion[..suggestion.len() - original.len()], common_suffix))
320    } else {
321        None
322    }
323}
324
325impl CodeSuggestion {
326    pub(crate) fn splice_lines(
329        &self,
330        sm: &SourceMap,
331    ) -> Vec<(String, Vec<TrimmedSubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, ConfusionType)>
332    {
333        use rustc_span::{CharPos, Pos};
338
339        fn push_trailing(
348            buf: &mut String,
349            line_opt: Option<&Cow<'_, str>>,
350            lo: &Loc,
351            hi_opt: Option<&Loc>,
352        ) -> usize {
353            let mut line_count = 0;
354            let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
357            if let Some(line) = line_opt {
358                if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
359                    let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
361                    match hi_opt {
362                        Some(hi) if hi > lo => {
364                            line_count = line[lo..hi].matches('\n').count();
366                            buf.push_str(&line[lo..hi])
367                        }
368                        Some(_) => (),
369                        None => {
371                            line_count = line[lo..].matches('\n').count();
373                            buf.push_str(&line[lo..])
374                        }
375                    }
376                }
377                if hi_opt.is_none() {
379                    buf.push('\n');
380                }
381            }
382            line_count
383        }
384
385        assert!(!self.substitutions.is_empty());
386
387        self.substitutions
388            .iter()
389            .filter(|subst| {
390                let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
393                if invalid {
394                    debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
395                }
396                !invalid
397            })
398            .cloned()
399            .filter_map(|mut substitution| {
400                substitution.parts.sort_by_key(|part| part.span.lo());
403
404                let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
406                let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
407                let bounding_span = Span::with_root_ctxt(lo, hi);
408                let lines = sm.span_to_lines(bounding_span).ok()?;
410                assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
411
412                if !sm.ensure_source_file_source_present(&lines.file) {
414                    return None;
415                }
416
417                let mut highlights = vec![];
418                let sf = &lines.file;
428                let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
429                prev_hi.col = CharPos::from_usize(0);
430                let mut prev_line =
431                    lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
432                let mut buf = String::new();
433
434                let mut line_highlight = vec![];
435                let mut acc = 0;
438                let mut confusion_type = ConfusionType::None;
439
440                let trimmed_parts = substitution
441                    .parts
442                    .into_iter()
443                    .map(|part| part.trim_trivial_replacements(sm))
447                    .collect::<Vec<_>>();
448
449                for part in &trimmed_parts {
450                    let part_confusion = detect_confusion_type(sm, &part.snippet, part.span);
451                    confusion_type = confusion_type.combine(part_confusion);
452                    let cur_lo = sm.lookup_char_pos(part.span.lo());
453                    if prev_hi.line == cur_lo.line {
454                        let mut count =
455                            push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
456                        while count > 0 {
457                            highlights.push(std::mem::take(&mut line_highlight));
458                            acc = 0;
459                            count -= 1;
460                        }
461                    } else {
462                        acc = 0;
463                        highlights.push(std::mem::take(&mut line_highlight));
464                        let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
465                        while count > 0 {
466                            highlights.push(std::mem::take(&mut line_highlight));
467                            count -= 1;
468                        }
469                        for idx in prev_hi.line..(cur_lo.line - 1) {
471                            if let Some(line) = sf.get_line(idx) {
472                                buf.push_str(line.as_ref());
473                                buf.push('\n');
474                                highlights.push(std::mem::take(&mut line_highlight));
475                            }
476                        }
477                        if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
478                            let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
479                                Some((i, _)) => i,
480                                None => cur_line.len(),
481                            };
482                            buf.push_str(&cur_line[..end]);
483                        }
484                    }
485                    let len: isize = part
487                        .snippet
488                        .split('\n')
489                        .next()
490                        .unwrap_or(&part.snippet)
491                        .chars()
492                        .map(|c| match c {
493                            '\t' => 4,
494                            _ => 1,
495                        })
496                        .sum();
497                    if !is_different(sm, &part.snippet, part.span) {
498                        } else {
502                        line_highlight.push(SubstitutionHighlight {
503                            start: (cur_lo.col.0 as isize + acc) as usize,
504                            end: (cur_lo.col.0 as isize + acc + len) as usize,
505                        });
506                    }
507                    buf.push_str(&part.snippet);
508                    let cur_hi = sm.lookup_char_pos(part.span.hi());
509                    acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
514                    prev_hi = cur_hi;
515                    prev_line = sf.get_line(prev_hi.line - 1);
516                    for line in part.snippet.split('\n').skip(1) {
517                        acc = 0;
518                        highlights.push(std::mem::take(&mut line_highlight));
519                        let end: usize = line
520                            .chars()
521                            .map(|c| match c {
522                                '\t' => 4,
523                                _ => 1,
524                            })
525                            .sum();
526                        line_highlight.push(SubstitutionHighlight { start: 0, end });
527                    }
528                }
529                highlights.push(std::mem::take(&mut line_highlight));
530                if !buf.ends_with('\n') {
532                    push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
533                }
534                while buf.ends_with('\n') {
536                    buf.pop();
537                }
538                if highlights.iter().all(|parts| parts.is_empty()) {
539                    None
540                } else {
541                    Some((buf, trimmed_parts, highlights, confusion_type))
542                }
543            })
544            .collect()
545    }
546}
547
548pub struct ExplicitBug;
551
552pub struct DelayedBugPanic;
555
556pub struct DiagCtxt {
560    inner: Lock<DiagCtxtInner>,
561}
562
563#[derive(Copy, Clone)]
564pub struct DiagCtxtHandle<'a> {
565    dcx: &'a DiagCtxt,
566    tainted_with_errors: Option<&'a Cell<Option<ErrorGuaranteed>>>,
569}
570
571impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
572    type Target = &'a DiagCtxt;
573
574    fn deref(&self) -> &Self::Target {
575        &self.dcx
576    }
577}
578
579struct DiagCtxtInner {
583    flags: DiagCtxtFlags,
584
585    registry: Registry,
586
587    err_guars: Vec<ErrorGuaranteed>,
589    lint_err_guars: Vec<ErrorGuaranteed>,
592    delayed_bugs: Vec<(DelayedDiagInner, ErrorGuaranteed)>,
594
595    deduplicated_err_count: usize,
597    deduplicated_warn_count: usize,
599
600    emitter: Box<DynEmitter>,
601
602    must_produce_diag: Option<Backtrace>,
605
606    has_printed: bool,
609
610    suppressed_expected_diag: bool,
613
614    taught_diagnostics: FxHashSet<ErrCode>,
618
619    emitted_diagnostic_codes: FxIndexSet<ErrCode>,
621
622    emitted_diagnostics: FxHashSet<Hash128>,
626
627    stashed_diagnostics:
633        FxIndexMap<StashKey, FxIndexMap<Span, (DiagInner, Option<ErrorGuaranteed>)>>,
634
635    future_breakage_diagnostics: Vec<DiagInner>,
636
637    fulfilled_expectations: FxIndexSet<LintExpectationId>,
649
650    ice_file: Option<PathBuf>,
653}
654
655#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
657pub enum StashKey {
658    ItemNoType,
659    UnderscoreForArrayLengths,
660    EarlySyntaxWarning,
661    CallIntoMethod,
662    LifetimeIsChar,
665    MaybeFruTypo,
668    CallAssocMethod,
669    AssociatedTypeSuggestion,
670    Cycle,
672    UndeterminedMacroResolution,
673    ExprInPat,
675    GenericInFieldExpr,
679}
680
681fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
682    (*f)(diag)
683}
684
685pub static TRACK_DIAGNOSTIC: AtomicRef<
688    fn(DiagInner, &mut dyn FnMut(DiagInner) -> Option<ErrorGuaranteed>) -> Option<ErrorGuaranteed>,
689> = AtomicRef::new(&(default_track_diagnostic as _));
690
691#[derive(Copy, Clone, Default)]
692pub struct DiagCtxtFlags {
693    pub can_emit_warnings: bool,
696    pub treat_err_as_bug: Option<NonZero<usize>>,
699    pub eagerly_emit_delayed_bugs: bool,
702    pub macro_backtrace: bool,
705    pub deduplicate_diagnostics: bool,
707    pub track_diagnostics: bool,
709}
710
711impl Drop for DiagCtxtInner {
712    fn drop(&mut self) {
713        self.emit_stashed_diagnostics();
721
722        self.flush_delayed();
726
727        if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
731            if let Some(backtrace) = &self.must_produce_diag {
732                let suggestion = match backtrace.status() {
733                    BacktraceStatus::Disabled => String::from(
734                        "Backtraces are currently disabled: set `RUST_BACKTRACE=1` and re-run \
735                        to see where it happened.",
736                    ),
737                    BacktraceStatus::Captured => format!(
738                        "This happened in the following `must_produce_diag` call's backtrace:\n\
739                        {backtrace}",
740                    ),
741                    _ => String::from("(impossible to capture backtrace where this happened)"),
742                };
743                panic!(
744                    "`trimmed_def_paths` called, diagnostics were expected but none were emitted. \
745                    Use `with_no_trimmed_paths` for debugging. {suggestion}"
746                );
747            }
748        }
749    }
750}
751
752impl DiagCtxt {
753    pub fn disable_warnings(mut self) -> Self {
754        self.inner.get_mut().flags.can_emit_warnings = false;
755        self
756    }
757
758    pub fn with_flags(mut self, flags: DiagCtxtFlags) -> Self {
759        self.inner.get_mut().flags = flags;
760        self
761    }
762
763    pub fn with_ice_file(mut self, ice_file: PathBuf) -> Self {
764        self.inner.get_mut().ice_file = Some(ice_file);
765        self
766    }
767
768    pub fn with_registry(mut self, registry: Registry) -> Self {
769        self.inner.get_mut().registry = registry;
770        self
771    }
772
773    pub fn new(emitter: Box<DynEmitter>) -> Self {
774        Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
775    }
776
777    pub fn make_silent(&self) {
778        let mut inner = self.inner.borrow_mut();
779        let translator = inner.emitter.translator().clone();
780        inner.emitter = Box::new(emitter::SilentEmitter { translator });
781    }
782
783    pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) {
784        self.inner.borrow_mut().emitter = emitter;
785    }
786
787    pub fn eagerly_translate<'a>(
789        &self,
790        message: DiagMessage,
791        args: impl Iterator<Item = DiagArg<'a>>,
792    ) -> SubdiagMessage {
793        let inner = self.inner.borrow();
794        inner.eagerly_translate(message, args)
795    }
796
797    pub fn eagerly_translate_to_string<'a>(
799        &self,
800        message: DiagMessage,
801        args: impl Iterator<Item = DiagArg<'a>>,
802    ) -> String {
803        let inner = self.inner.borrow();
804        inner.eagerly_translate_to_string(message, args)
805    }
806
807    pub fn can_emit_warnings(&self) -> bool {
811        self.inner.borrow_mut().flags.can_emit_warnings
812    }
813
814    pub fn reset_err_count(&self) {
820        let mut inner = self.inner.borrow_mut();
823        let DiagCtxtInner {
824            flags: _,
825            registry: _,
826            err_guars,
827            lint_err_guars,
828            delayed_bugs,
829            deduplicated_err_count,
830            deduplicated_warn_count,
831            emitter: _,
832            must_produce_diag,
833            has_printed,
834            suppressed_expected_diag,
835            taught_diagnostics,
836            emitted_diagnostic_codes,
837            emitted_diagnostics,
838            stashed_diagnostics,
839            future_breakage_diagnostics,
840            fulfilled_expectations,
841            ice_file: _,
842        } = inner.deref_mut();
843
844        *err_guars = Default::default();
847        *lint_err_guars = Default::default();
848        *delayed_bugs = Default::default();
849        *deduplicated_err_count = 0;
850        *deduplicated_warn_count = 0;
851        *must_produce_diag = None;
852        *has_printed = false;
853        *suppressed_expected_diag = false;
854        *taught_diagnostics = Default::default();
855        *emitted_diagnostic_codes = Default::default();
856        *emitted_diagnostics = Default::default();
857        *stashed_diagnostics = Default::default();
858        *future_breakage_diagnostics = Default::default();
859        *fulfilled_expectations = Default::default();
860    }
861
862    pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> {
863        DiagCtxtHandle { dcx: self, tainted_with_errors: None }
864    }
865
866    pub fn taintable_handle<'a>(
870        &'a self,
871        tainted_with_errors: &'a Cell<Option<ErrorGuaranteed>>,
872    ) -> DiagCtxtHandle<'a> {
873        DiagCtxtHandle { dcx: self, tainted_with_errors: Some(tainted_with_errors) }
874    }
875}
876
877impl<'a> DiagCtxtHandle<'a> {
878    pub fn stash_diagnostic(
900        &self,
901        span: Span,
902        key: StashKey,
903        diag: DiagInner,
904    ) -> Option<ErrorGuaranteed> {
905        let guar = match diag.level {
906            Bug | Fatal => {
907                self.span_bug(
908                    span,
909                    format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
910                );
911            }
912            Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
916            DelayedBug => {
917                return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors);
918            }
919            ForceWarning | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
920            | Expect => None,
921        };
922
923        self.inner
927            .borrow_mut()
928            .stashed_diagnostics
929            .entry(key)
930            .or_default()
931            .insert(span.with_parent(None), (diag, guar));
932
933        guar
934    }
935
936    pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
940        let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
942            |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
943        )?;
944        assert!(!diag.is_error());
945        assert!(guar.is_none());
946        Some(Diag::new_diagnostic(self, diag))
947    }
948
949    pub fn try_steal_modify_and_emit_err<F>(
954        self,
955        span: Span,
956        key: StashKey,
957        mut modify_err: F,
958    ) -> Option<ErrorGuaranteed>
959    where
960        F: FnMut(&mut Diag<'_>),
961    {
962        let err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
964            |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
965        );
966        err.map(|(err, guar)| {
967            assert_eq!(err.level, Error);
969            assert!(guar.is_some());
970            let mut err = Diag::<ErrorGuaranteed>::new_diagnostic(self, err);
971            modify_err(&mut err);
972            assert_eq!(err.level, Error);
973            err.emit()
974        })
975    }
976
977    pub fn try_steal_replace_and_emit_err(
981        self,
982        span: Span,
983        key: StashKey,
984        new_err: Diag<'_>,
985    ) -> ErrorGuaranteed {
986        let old_err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
988            |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
989        );
990        match old_err {
991            Some((old_err, guar)) => {
992                assert_eq!(old_err.level, Error);
993                assert!(guar.is_some());
994                Diag::<ErrorGuaranteed>::new_diagnostic(self, old_err).cancel();
997            }
998            None => {}
999        };
1000        new_err.emit()
1001    }
1002
1003    pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
1004        let inner = self.inner.borrow();
1005        if let Some(stashed_diagnostics) = inner.stashed_diagnostics.get(&key)
1006            && !stashed_diagnostics.is_empty()
1007        {
1008            stashed_diagnostics.contains_key(&span.with_parent(None))
1009        } else {
1010            false
1011        }
1012    }
1013
1014    pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
1016        self.inner.borrow_mut().emit_stashed_diagnostics()
1017    }
1018
1019    #[inline]
1021    pub fn err_count(&self) -> usize {
1022        let inner = self.inner.borrow();
1023        inner.err_guars.len()
1024            + inner.lint_err_guars.len()
1025            + inner
1026                .stashed_diagnostics
1027                .values()
1028                .map(|a| a.values().filter(|(_, guar)| guar.is_some()).count())
1029                .sum::<usize>()
1030    }
1031
1032    pub fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1035        self.inner.borrow().has_errors_excluding_lint_errors()
1036    }
1037
1038    pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
1040        self.inner.borrow().has_errors()
1041    }
1042
1043    pub fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1046        self.inner.borrow().has_errors_or_delayed_bugs()
1047    }
1048
1049    pub fn print_error_count(&self) {
1050        let mut inner = self.inner.borrow_mut();
1051
1052        assert!(inner.stashed_diagnostics.is_empty());
1055
1056        if inner.treat_err_as_bug() {
1057            return;
1058        }
1059
1060        let warnings = match inner.deduplicated_warn_count {
1061            0 => Cow::from(""),
1062            1 => Cow::from("1 warning emitted"),
1063            count => Cow::from(format!("{count} warnings emitted")),
1064        };
1065        let errors = match inner.deduplicated_err_count {
1066            0 => Cow::from(""),
1067            1 => Cow::from("aborting due to 1 previous error"),
1068            count => Cow::from(format!("aborting due to {count} previous errors")),
1069        };
1070
1071        match (errors.len(), warnings.len()) {
1072            (0, 0) => return,
1073            (0, _) => {
1074                inner.emit_diagnostic(
1077                    DiagInner::new(ForceWarning, DiagMessage::Str(warnings)),
1078                    None,
1079                );
1080            }
1081            (_, 0) => {
1082                inner.emit_diagnostic(DiagInner::new(Error, errors), self.tainted_with_errors);
1083            }
1084            (_, _) => {
1085                inner.emit_diagnostic(
1086                    DiagInner::new(Error, format!("{errors}; {warnings}")),
1087                    self.tainted_with_errors,
1088                );
1089            }
1090        }
1091
1092        let can_show_explain = inner.emitter.should_show_explain();
1093        let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty();
1094        if can_show_explain && are_there_diagnostics {
1095            let mut error_codes = inner
1096                .emitted_diagnostic_codes
1097                .iter()
1098                .filter_map(|&code| {
1099                    if inner.registry.try_find_description(code).is_ok() {
1100                        Some(code.to_string())
1101                    } else {
1102                        None
1103                    }
1104                })
1105                .collect::<Vec<_>>();
1106            if !error_codes.is_empty() {
1107                error_codes.sort();
1108                if error_codes.len() > 1 {
1109                    let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
1110                    let msg1 = format!(
1111                        "Some errors have detailed explanations: {}{}",
1112                        error_codes[..limit].join(", "),
1113                        if error_codes.len() > 9 { "..." } else { "." }
1114                    );
1115                    let msg2 = format!(
1116                        "For more information about an error, try `rustc --explain {}`.",
1117                        &error_codes[0]
1118                    );
1119                    inner.emit_diagnostic(DiagInner::new(FailureNote, msg1), None);
1120                    inner.emit_diagnostic(DiagInner::new(FailureNote, msg2), None);
1121                } else {
1122                    let msg = format!(
1123                        "For more information about this error, try `rustc --explain {}`.",
1124                        &error_codes[0]
1125                    );
1126                    inner.emit_diagnostic(DiagInner::new(FailureNote, msg), None);
1127                }
1128            }
1129        }
1130    }
1131
1132    pub fn abort_if_errors(&self) {
1137        if let Some(guar) = self.has_errors() {
1138            guar.raise_fatal();
1139        }
1140    }
1141
1142    pub fn must_teach(&self, code: ErrCode) -> bool {
1148        self.inner.borrow_mut().taught_diagnostics.insert(code)
1149    }
1150
1151    pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
1152        self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors)
1153    }
1154
1155    pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
1156        self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
1157    }
1158
1159    pub fn emit_timing_section_start(&self, record: TimingRecord) {
1160        self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::Start);
1161    }
1162
1163    pub fn emit_timing_section_end(&self, record: TimingRecord) {
1164        self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::End);
1165    }
1166
1167    pub fn emit_future_breakage_report(&self) {
1168        let inner = &mut *self.inner.borrow_mut();
1169        let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
1170        if !diags.is_empty() {
1171            inner.emitter.emit_future_breakage_report(diags, &inner.registry);
1172        }
1173    }
1174
1175    pub fn emit_unused_externs(
1176        &self,
1177        lint_level: rustc_lint_defs::Level,
1178        loud: bool,
1179        unused_externs: &[&str],
1180    ) {
1181        let mut inner = self.inner.borrow_mut();
1182
1183        if loud && lint_level.is_error() {
1194            #[allow(deprecated)]
1197            inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
1198            inner.panic_if_treat_err_as_bug();
1199        }
1200
1201        inner.emitter.emit_unused_externs(lint_level, unused_externs)
1202    }
1203
1204    #[must_use]
1207    pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
1208        std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
1209    }
1210
1211    pub fn flush_delayed(&self) {
1212        self.inner.borrow_mut().flush_delayed();
1213    }
1214
1215    #[track_caller]
1218    pub fn set_must_produce_diag(&self) {
1219        assert!(
1220            self.inner.borrow().must_produce_diag.is_none(),
1221            "should only need to collect a backtrace once"
1222        );
1223        self.inner.borrow_mut().must_produce_diag = Some(Backtrace::capture());
1224    }
1225}
1226
1227impl<'a> DiagCtxtHandle<'a> {
1232    #[track_caller]
1235    pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> {
1236        Diag::new(self, Bug, msg.into())
1237    }
1238
1239    #[track_caller]
1242    pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
1243        self.struct_bug(msg).emit()
1244    }
1245
1246    #[track_caller]
1249    pub fn struct_span_bug(
1250        self,
1251        span: impl Into<MultiSpan>,
1252        msg: impl Into<Cow<'static, str>>,
1253    ) -> Diag<'a, BugAbort> {
1254        self.struct_bug(msg).with_span(span)
1255    }
1256
1257    #[track_caller]
1260    pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
1261        self.struct_span_bug(span, msg.into()).emit()
1262    }
1263
1264    #[track_caller]
1265    pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> {
1266        bug.into_diag(self, Bug)
1267    }
1268
1269    #[track_caller]
1270    pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! {
1271        self.create_bug(bug).emit()
1272    }
1273
1274    #[rustc_lint_diagnostics]
1275    #[track_caller]
1276    pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> {
1277        Diag::new(self, Fatal, msg)
1278    }
1279
1280    #[rustc_lint_diagnostics]
1281    #[track_caller]
1282    pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
1283        self.struct_fatal(msg).emit()
1284    }
1285
1286    #[rustc_lint_diagnostics]
1287    #[track_caller]
1288    pub fn struct_span_fatal(
1289        self,
1290        span: impl Into<MultiSpan>,
1291        msg: impl Into<DiagMessage>,
1292    ) -> Diag<'a, FatalAbort> {
1293        self.struct_fatal(msg).with_span(span)
1294    }
1295
1296    #[rustc_lint_diagnostics]
1297    #[track_caller]
1298    pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
1299        self.struct_span_fatal(span, msg).emit()
1300    }
1301
1302    #[track_caller]
1303    pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> {
1304        fatal.into_diag(self, Fatal)
1305    }
1306
1307    #[track_caller]
1308    pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
1309        self.create_fatal(fatal).emit()
1310    }
1311
1312    #[track_caller]
1313    pub fn create_almost_fatal(
1314        self,
1315        fatal: impl Diagnostic<'a, FatalError>,
1316    ) -> Diag<'a, FatalError> {
1317        fatal.into_diag(self, Fatal)
1318    }
1319
1320    #[track_caller]
1321    pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError {
1322        self.create_almost_fatal(fatal).emit()
1323    }
1324
1325    #[rustc_lint_diagnostics]
1327    #[track_caller]
1328    pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> {
1329        Diag::new(self, Error, msg)
1330    }
1331
1332    #[rustc_lint_diagnostics]
1333    #[track_caller]
1334    pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
1335        self.struct_err(msg).emit()
1336    }
1337
1338    #[rustc_lint_diagnostics]
1339    #[track_caller]
1340    pub fn struct_span_err(
1341        self,
1342        span: impl Into<MultiSpan>,
1343        msg: impl Into<DiagMessage>,
1344    ) -> Diag<'a> {
1345        self.struct_err(msg).with_span(span)
1346    }
1347
1348    #[rustc_lint_diagnostics]
1349    #[track_caller]
1350    pub fn span_err(
1351        self,
1352        span: impl Into<MultiSpan>,
1353        msg: impl Into<DiagMessage>,
1354    ) -> ErrorGuaranteed {
1355        self.struct_span_err(span, msg).emit()
1356    }
1357
1358    #[track_caller]
1359    pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> {
1360        err.into_diag(self, Error)
1361    }
1362
1363    #[track_caller]
1364    pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
1365        self.create_err(err).emit()
1366    }
1367
1368    #[track_caller]
1373    pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
1374        Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
1375    }
1376
1377    #[track_caller]
1385    pub fn span_delayed_bug(
1386        self,
1387        sp: impl Into<MultiSpan>,
1388        msg: impl Into<Cow<'static, str>>,
1389    ) -> ErrorGuaranteed {
1390        Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
1391    }
1392
1393    #[rustc_lint_diagnostics]
1394    #[track_caller]
1395    pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1396        Diag::new(self, Warning, msg)
1397    }
1398
1399    #[rustc_lint_diagnostics]
1400    #[track_caller]
1401    pub fn warn(self, msg: impl Into<DiagMessage>) {
1402        self.struct_warn(msg).emit()
1403    }
1404
1405    #[rustc_lint_diagnostics]
1406    #[track_caller]
1407    pub fn struct_span_warn(
1408        self,
1409        span: impl Into<MultiSpan>,
1410        msg: impl Into<DiagMessage>,
1411    ) -> Diag<'a, ()> {
1412        self.struct_warn(msg).with_span(span)
1413    }
1414
1415    #[rustc_lint_diagnostics]
1416    #[track_caller]
1417    pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1418        self.struct_span_warn(span, msg).emit()
1419    }
1420
1421    #[track_caller]
1422    pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1423        warning.into_diag(self, Warning)
1424    }
1425
1426    #[track_caller]
1427    pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) {
1428        self.create_warn(warning).emit()
1429    }
1430
1431    #[rustc_lint_diagnostics]
1432    #[track_caller]
1433    pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1434        Diag::new(self, Note, msg)
1435    }
1436
1437    #[rustc_lint_diagnostics]
1438    #[track_caller]
1439    pub fn note(&self, msg: impl Into<DiagMessage>) {
1440        self.struct_note(msg).emit()
1441    }
1442
1443    #[rustc_lint_diagnostics]
1444    #[track_caller]
1445    pub fn struct_span_note(
1446        self,
1447        span: impl Into<MultiSpan>,
1448        msg: impl Into<DiagMessage>,
1449    ) -> Diag<'a, ()> {
1450        self.struct_note(msg).with_span(span)
1451    }
1452
1453    #[rustc_lint_diagnostics]
1454    #[track_caller]
1455    pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1456        self.struct_span_note(span, msg).emit()
1457    }
1458
1459    #[track_caller]
1460    pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1461        note.into_diag(self, Note)
1462    }
1463
1464    #[track_caller]
1465    pub fn emit_note(self, note: impl Diagnostic<'a, ()>) {
1466        self.create_note(note).emit()
1467    }
1468
1469    #[rustc_lint_diagnostics]
1470    #[track_caller]
1471    pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1472        Diag::new(self, Help, msg)
1473    }
1474
1475    #[rustc_lint_diagnostics]
1476    #[track_caller]
1477    pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1478        Diag::new(self, FailureNote, msg)
1479    }
1480
1481    #[rustc_lint_diagnostics]
1482    #[track_caller]
1483    pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1484        Diag::new(self, Allow, msg)
1485    }
1486
1487    #[rustc_lint_diagnostics]
1488    #[track_caller]
1489    pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> {
1490        Diag::new(self, Expect, msg).with_lint_id(id)
1491    }
1492}
1493
1494impl DiagCtxtInner {
1499    fn new(emitter: Box<DynEmitter>) -> Self {
1500        Self {
1501            flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
1502            registry: Registry::new(&[]),
1503            err_guars: Vec::new(),
1504            lint_err_guars: Vec::new(),
1505            delayed_bugs: Vec::new(),
1506            deduplicated_err_count: 0,
1507            deduplicated_warn_count: 0,
1508            emitter,
1509            must_produce_diag: None,
1510            has_printed: false,
1511            suppressed_expected_diag: false,
1512            taught_diagnostics: Default::default(),
1513            emitted_diagnostic_codes: Default::default(),
1514            emitted_diagnostics: Default::default(),
1515            stashed_diagnostics: Default::default(),
1516            future_breakage_diagnostics: Vec::new(),
1517            fulfilled_expectations: Default::default(),
1518            ice_file: None,
1519        }
1520    }
1521
1522    fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
1524        let mut guar = None;
1525        let has_errors = !self.err_guars.is_empty();
1526        for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
1527            for (_, (diag, _guar)) in stashed_diagnostics {
1528                if !diag.is_error() {
1529                    if !diag.is_force_warn() && has_errors {
1533                        continue;
1534                    }
1535                }
1536                guar = guar.or(self.emit_diagnostic(diag, None));
1537            }
1538        }
1539        guar
1540    }
1541
1542    fn emit_diagnostic(
1544        &mut self,
1545        mut diagnostic: DiagInner,
1546        taint: Option<&Cell<Option<ErrorGuaranteed>>>,
1547    ) -> Option<ErrorGuaranteed> {
1548        if diagnostic.has_future_breakage() {
1549            assert_matches!(diagnostic.level, Error | ForceWarning | Warning | Allow | Expect);
1553            self.future_breakage_diagnostics.push(diagnostic.clone());
1554        }
1555
1556        match diagnostic.level {
1560            Bug => {}
1561            Fatal | Error => {
1562                if self.treat_next_err_as_bug() {
1563                    diagnostic.level = Bug;
1565                }
1566            }
1567            DelayedBug => {
1568                if self.flags.eagerly_emit_delayed_bugs {
1573                    if self.treat_next_err_as_bug() {
1575                        diagnostic.level = Bug;
1576                    } else {
1577                        diagnostic.level = Error;
1578                    }
1579                } else {
1580                    return if let Some(guar) = self.has_errors() {
1583                        Some(guar)
1584                    } else {
1585                        let backtrace = std::backtrace::Backtrace::capture();
1589                        #[allow(deprecated)]
1593                        let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1594                        self.delayed_bugs
1595                            .push((DelayedDiagInner::with_backtrace(diagnostic, backtrace), guar));
1596                        Some(guar)
1597                    };
1598                }
1599            }
1600            ForceWarning if diagnostic.lint_id.is_none() => {} Warning => {
1602                if !self.flags.can_emit_warnings {
1603                    if diagnostic.has_future_breakage() {
1605                        TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1607                    }
1608                    return None;
1609                }
1610            }
1611            Note | Help | FailureNote => {}
1612            OnceNote | OnceHelp => panic!("bad level: {:?}", diagnostic.level),
1613            Allow => {
1614                if diagnostic.has_future_breakage() {
1616                    TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1618                    self.suppressed_expected_diag = true;
1619                }
1620                return None;
1621            }
1622            Expect | ForceWarning => {
1623                self.fulfilled_expectations.insert(diagnostic.lint_id.unwrap());
1624                if let Expect = diagnostic.level {
1625                    TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1627                    self.suppressed_expected_diag = true;
1628                    return None;
1629                }
1630            }
1631        }
1632
1633        TRACK_DIAGNOSTIC(diagnostic, &mut |mut diagnostic| {
1634            if let Some(code) = diagnostic.code {
1635                self.emitted_diagnostic_codes.insert(code);
1636            }
1637
1638            let already_emitted = {
1639                let mut hasher = StableHasher::new();
1640                diagnostic.hash(&mut hasher);
1641                let diagnostic_hash = hasher.finish();
1642                !self.emitted_diagnostics.insert(diagnostic_hash)
1643            };
1644
1645            let is_error = diagnostic.is_error();
1646            let is_lint = diagnostic.is_lint.is_some();
1647
1648            if !(self.flags.deduplicate_diagnostics && already_emitted) {
1651                debug!(?diagnostic);
1652                debug!(?self.emitted_diagnostics);
1653
1654                let not_yet_emitted = |sub: &mut Subdiag| {
1655                    debug!(?sub);
1656                    if sub.level != OnceNote && sub.level != OnceHelp {
1657                        return true;
1658                    }
1659                    let mut hasher = StableHasher::new();
1660                    sub.hash(&mut hasher);
1661                    let diagnostic_hash = hasher.finish();
1662                    debug!(?diagnostic_hash);
1663                    self.emitted_diagnostics.insert(diagnostic_hash)
1664                };
1665                diagnostic.children.retain_mut(not_yet_emitted);
1666                if already_emitted {
1667                    let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`";
1668                    diagnostic.sub(Note, msg, MultiSpan::new());
1669                }
1670
1671                if is_error {
1672                    self.deduplicated_err_count += 1;
1673                } else if matches!(diagnostic.level, ForceWarning | Warning) {
1674                    self.deduplicated_warn_count += 1;
1675                }
1676                self.has_printed = true;
1677
1678                self.emitter.emit_diagnostic(diagnostic, &self.registry);
1679            }
1680
1681            if is_error {
1682                if !self.delayed_bugs.is_empty() {
1687                    assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0);
1688                    self.delayed_bugs.clear();
1689                    self.delayed_bugs.shrink_to_fit();
1690                }
1691
1692                #[allow(deprecated)]
1695                let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1696                if is_lint {
1697                    self.lint_err_guars.push(guar);
1698                } else {
1699                    if let Some(taint) = taint {
1700                        taint.set(Some(guar));
1701                    }
1702                    self.err_guars.push(guar);
1703                }
1704                self.panic_if_treat_err_as_bug();
1705                Some(guar)
1706            } else {
1707                None
1708            }
1709        })
1710    }
1711
1712    fn treat_err_as_bug(&self) -> bool {
1713        self.flags
1714            .treat_err_as_bug
1715            .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
1716    }
1717
1718    fn treat_next_err_as_bug(&self) -> bool {
1720        self.flags
1721            .treat_err_as_bug
1722            .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
1723    }
1724
1725    fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1726        self.err_guars.get(0).copied().or_else(|| {
1727            if let Some((_diag, guar)) = self
1728                .stashed_diagnostics
1729                .values()
1730                .flat_map(|stashed_diagnostics| stashed_diagnostics.values())
1731                .find(|(diag, guar)| guar.is_some() && diag.is_lint.is_none())
1732            {
1733                *guar
1734            } else {
1735                None
1736            }
1737        })
1738    }
1739
1740    fn has_errors(&self) -> Option<ErrorGuaranteed> {
1741        self.err_guars.get(0).copied().or_else(|| self.lint_err_guars.get(0).copied()).or_else(
1742            || {
1743                self.stashed_diagnostics.values().find_map(|stashed_diagnostics| {
1744                    stashed_diagnostics.values().find_map(|(_, guar)| *guar)
1745                })
1746            },
1747        )
1748    }
1749
1750    fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1751        self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
1752    }
1753
1754    fn eagerly_translate<'a>(
1756        &self,
1757        message: DiagMessage,
1758        args: impl Iterator<Item = DiagArg<'a>>,
1759    ) -> SubdiagMessage {
1760        SubdiagMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
1761    }
1762
1763    fn eagerly_translate_to_string<'a>(
1765        &self,
1766        message: DiagMessage,
1767        args: impl Iterator<Item = DiagArg<'a>>,
1768    ) -> String {
1769        let args = crate::translation::to_fluent_args(args);
1770        self.emitter
1771            .translator()
1772            .translate_message(&message, &args)
1773            .map_err(Report::new)
1774            .unwrap()
1775            .to_string()
1776    }
1777
1778    fn eagerly_translate_for_subdiag(
1779        &self,
1780        diag: &DiagInner,
1781        msg: impl Into<SubdiagMessage>,
1782    ) -> SubdiagMessage {
1783        let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
1784        self.eagerly_translate(msg, diag.args.iter())
1785    }
1786
1787    fn flush_delayed(&mut self) {
1788        assert!(self.stashed_diagnostics.is_empty());
1792
1793        if !self.err_guars.is_empty() {
1794            return;
1796        }
1797
1798        if self.delayed_bugs.is_empty() {
1799            return;
1801        }
1802
1803        let bugs: Vec<_> =
1804            std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
1805
1806        let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0"));
1807        let decorate = backtrace || self.ice_file.is_none();
1808        let mut out = self
1809            .ice_file
1810            .as_ref()
1811            .and_then(|file| std::fs::File::options().create(true).append(true).open(file).ok());
1812
1813        let note1 = "no errors encountered even though delayed bugs were created";
1818        let note2 = "those delayed bugs will now be shown as internal compiler errors";
1819        self.emit_diagnostic(DiagInner::new(Note, note1), None);
1820        self.emit_diagnostic(DiagInner::new(Note, note2), None);
1821
1822        for bug in bugs {
1823            if let Some(out) = &mut out {
1824                _ = write!(
1825                    out,
1826                    "delayed bug: {}\n{}\n",
1827                    bug.inner
1828                        .messages
1829                        .iter()
1830                        .filter_map(|(msg, _)| msg.as_str())
1831                        .collect::<String>(),
1832                    &bug.note
1833                );
1834            }
1835
1836            let mut bug = if decorate { bug.decorate(self) } else { bug.inner };
1837
1838            if bug.level != DelayedBug {
1840                bug.arg("level", bug.level);
1847                let msg = crate::fluent_generated::errors_invalid_flushed_delayed_diagnostic_level;
1848                let msg = self.eagerly_translate_for_subdiag(&bug, msg); bug.sub(Note, msg, bug.span.primary_span().unwrap().into());
1850            }
1851            bug.level = Bug;
1852
1853            self.emit_diagnostic(bug, None);
1854        }
1855
1856        panic::panic_any(DelayedBugPanic);
1858    }
1859
1860    fn panic_if_treat_err_as_bug(&self) {
1861        if self.treat_err_as_bug() {
1862            let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
1863            assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
1864            if n == 1 {
1865                panic!("aborting due to `-Z treat-err-as-bug=1`");
1866            } else {
1867                panic!("aborting after {n} errors due to `-Z treat-err-as-bug={n}`");
1868            }
1869        }
1870    }
1871}
1872
1873struct DelayedDiagInner {
1874    inner: DiagInner,
1875    note: Backtrace,
1876}
1877
1878impl DelayedDiagInner {
1879    fn with_backtrace(diagnostic: DiagInner, backtrace: Backtrace) -> Self {
1880        DelayedDiagInner { inner: diagnostic, note: backtrace }
1881    }
1882
1883    fn decorate(self, dcx: &DiagCtxtInner) -> DiagInner {
1884        let mut diag = self.inner;
1888        let msg = match self.note.status() {
1889            BacktraceStatus::Captured => crate::fluent_generated::errors_delayed_at_with_newline,
1890            _ => crate::fluent_generated::errors_delayed_at_without_newline,
1893        };
1894        diag.arg("emitted_at", diag.emitted_at.clone());
1895        diag.arg("note", self.note);
1896        let msg = dcx.eagerly_translate_for_subdiag(&diag, msg); diag.sub(Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into());
1898        diag
1899    }
1900}
1901
1902#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
1922pub enum Level {
1923    Bug,
1925
1926    Fatal,
1929
1930    Error,
1933
1934    DelayedBug,
1939
1940    ForceWarning,
1946
1947    Warning,
1950
1951    Note,
1953
1954    OnceNote,
1956
1957    Help,
1959
1960    OnceHelp,
1962
1963    FailureNote,
1966
1967    Allow,
1969
1970    Expect,
1972}
1973
1974impl fmt::Display for Level {
1975    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1976        self.to_str().fmt(f)
1977    }
1978}
1979
1980impl Level {
1981    fn color(self) -> anstyle::Style {
1982        match self {
1983            Bug | Fatal | Error | DelayedBug => AnsiColor::BrightRed.on_default(),
1984            ForceWarning | Warning => {
1985                if cfg!(windows) {
1986                    AnsiColor::BrightYellow.on_default()
1987                } else {
1988                    AnsiColor::Yellow.on_default()
1989                }
1990            }
1991            Note | OnceNote => AnsiColor::BrightGreen.on_default(),
1992            Help | OnceHelp => AnsiColor::BrightCyan.on_default(),
1993            FailureNote => anstyle::Style::new(),
1994            Allow | Expect => unreachable!(),
1995        }
1996    }
1997
1998    pub fn to_str(self) -> &'static str {
1999        match self {
2000            Bug | DelayedBug => "error: internal compiler error",
2001            Fatal | Error => "error",
2002            ForceWarning | Warning => "warning",
2003            Note | OnceNote => "note",
2004            Help | OnceHelp => "help",
2005            FailureNote => "failure-note",
2006            Allow | Expect => unreachable!(),
2007        }
2008    }
2009
2010    pub fn is_failure_note(&self) -> bool {
2011        matches!(*self, FailureNote)
2012    }
2013
2014    fn can_be_subdiag(&self) -> bool {
2016        match self {
2017            Bug | DelayedBug | Fatal | Error | ForceWarning | FailureNote | Allow | Expect => false,
2018
2019            Warning | Note | Help | OnceNote | OnceHelp => true,
2020        }
2021    }
2022}
2023
2024impl IntoDiagArg for Level {
2025    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
2026        DiagArgValue::Str(Cow::from(self.to_string()))
2027    }
2028}
2029
2030pub fn elided_lifetime_in_path_suggestion(
2032    source_map: &SourceMap,
2033    n: usize,
2034    path_span: Span,
2035    incl_angl_brckt: bool,
2036    insertion_span: Span,
2037) -> ElidedLifetimeInPathSubdiag {
2038    let expected = ExpectedLifetimeParameter { span: path_span, count: n };
2039    let indicate = source_map.is_span_accessible(insertion_span).then(|| {
2041        let anon_lts = vec!["'_"; n].join(", ");
2042        let suggestion =
2043            if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
2044
2045        IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
2046    });
2047
2048    ElidedLifetimeInPathSubdiag { expected, indicate }
2049}
2050
2051pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
2052    diag: &mut Diag<'a, G>,
2053    ambiguity: rustc_lint_defs::AmbiguityErrorDiag,
2054) {
2055    diag.span_label(ambiguity.label_span, ambiguity.label_msg);
2056    diag.note(ambiguity.note_msg);
2057    diag.span_note(ambiguity.b1_span, ambiguity.b1_note_msg);
2058    for help_msg in ambiguity.b1_help_msgs {
2059        diag.help(help_msg);
2060    }
2061    diag.span_note(ambiguity.b2_span, ambiguity.b2_note_msg);
2062    for help_msg in ambiguity.b2_help_msgs {
2063        diag.help(help_msg);
2064    }
2065}
2066
2067pub fn a_or_an(s: &str) -> &'static str {
2071    let mut chars = s.chars();
2072    let Some(mut first_alpha_char) = chars.next() else {
2073        return "a";
2074    };
2075    if first_alpha_char == '`' {
2076        let Some(next) = chars.next() else {
2077            return "a";
2078        };
2079        first_alpha_char = next;
2080    }
2081    if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
2082        "an"
2083    } else {
2084        "a"
2085    }
2086}
2087
2088#[derive(Clone, Copy, PartialEq, Hash, Debug)]
2089pub enum TerminalUrl {
2090    No,
2091    Yes,
2092    Auto,
2093}