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 codes::*;
43pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
44pub use diagnostic::{
45    BugAbort, Diag, DiagArgMap, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee,
46    FatalAbort, LintDiagnostic, LintDiagnosticBox, StringPart, Subdiag, Subdiagnostic,
47};
48pub use diagnostic_impls::{
49    DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
50    IndicateAnonymousLifetime, SingleLabelManySpans,
51};
52pub use emitter::ColorConfig;
53use emitter::{ConfusionType, DynEmitter, Emitter, detect_confusion_type, is_different};
54use rustc_data_structures::AtomicRef;
55use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
56use rustc_data_structures::stable_hasher::StableHasher;
57use rustc_data_structures::sync::{DynSend, Lock};
58pub use rustc_error_messages::{
59    DiagArg, DiagArgFromDisplay, DiagArgName, DiagArgValue, DiagMessage, FluentBundle, IntoDiagArg,
60    LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage,
61    fallback_fluent_bundle, fluent_bundle, into_diag_arg_using_display,
62};
63use rustc_hashes::Hash128;
64pub use rustc_lint_defs::{Applicability, listify, pluralize};
65use rustc_lint_defs::{Lint, LintExpectationId};
66use rustc_macros::{Decodable, Encodable};
67pub use rustc_span::ErrorGuaranteed;
68pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
69use rustc_span::source_map::SourceMap;
70use rustc_span::{BytePos, DUMMY_SP, Loc, Span};
71pub use snippet::Style;
72pub use termcolor::{Color, ColorSpec, WriteColor};
75use tracing::debug;
76
77use crate::emitter::TimingEvent;
78use crate::registry::Registry;
79use crate::timings::TimingRecord;
80
81pub mod annotate_snippet_emitter_writer;
82pub mod codes;
83mod decorate_diag;
84mod diagnostic;
85mod diagnostic_impls;
86pub mod emitter;
87pub mod error;
88pub mod json;
89mod lock;
90pub mod markdown;
91pub mod registry;
92mod snippet;
93mod styled_buffer;
94#[cfg(test)]
95mod tests;
96pub mod timings;
97pub mod translation;
98
99pub type PResult<'a, T> = Result<T, Diag<'a>>;
100
101rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
102
103#[cfg(target_pointer_width = "64")]
105rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24);
106#[cfg(target_pointer_width = "64")]
107rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24);
108
109pub trait LintEmitter: Copy {
112    type Id: Copy;
113    #[track_caller]
114    fn emit_node_span_lint(
115        self,
116        lint: &'static Lint,
117        hir_id: Self::Id,
118        span: impl Into<MultiSpan>,
119        decorator: impl for<'a> LintDiagnostic<'a, ()> + DynSend + 'static,
120    );
121}
122
123#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
124pub enum SuggestionStyle {
125    HideCodeInline,
127    HideCodeAlways,
129    CompletelyHidden,
131    ShowCode,
135    ShowAlways,
137}
138
139impl SuggestionStyle {
140    fn hide_inline(&self) -> bool {
141        !matches!(*self, SuggestionStyle::ShowCode)
142    }
143}
144
145#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
147pub enum Suggestions {
148    Enabled(Vec<CodeSuggestion>),
153    Sealed(Box<[CodeSuggestion]>),
157    Disabled,
161}
162
163impl Suggestions {
164    pub fn unwrap_tag(self) -> Vec<CodeSuggestion> {
166        match self {
167            Suggestions::Enabled(suggestions) => suggestions,
168            Suggestions::Sealed(suggestions) => suggestions.into_vec(),
169            Suggestions::Disabled => Vec::new(),
170        }
171    }
172}
173
174impl Default for Suggestions {
175    fn default() -> Self {
176        Self::Enabled(vec![])
177    }
178}
179
180#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
181pub struct CodeSuggestion {
182    pub substitutions: Vec<Substitution>,
204    pub msg: DiagMessage,
205    pub style: SuggestionStyle,
207    pub applicability: Applicability,
213}
214
215#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
216pub struct Substitution {
218    pub parts: Vec<SubstitutionPart>,
219}
220
221#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
222pub struct SubstitutionPart {
223    pub span: Span,
224    pub snippet: String,
225}
226
227#[derive(Debug, Clone, Copy)]
230pub(crate) struct SubstitutionHighlight {
231    start: usize,
232    end: usize,
233}
234
235impl SubstitutionPart {
236    pub fn is_addition(&self, sm: &SourceMap) -> bool {
237        !self.snippet.is_empty() && !self.replaces_meaningful_content(sm)
238    }
239
240    pub fn is_deletion(&self, sm: &SourceMap) -> bool {
241        self.snippet.trim().is_empty() && self.replaces_meaningful_content(sm)
242    }
243
244    pub fn is_replacement(&self, sm: &SourceMap) -> bool {
245        !self.snippet.is_empty() && self.replaces_meaningful_content(sm)
246    }
247
248    pub fn is_destructive_replacement(&self, sm: &SourceMap) -> bool {
253        self.is_replacement(sm)
254            && !sm
255                .span_to_snippet(self.span)
256                .is_ok_and(|snippet| as_substr(snippet.trim(), self.snippet.trim()).is_some())
257    }
258
259    fn replaces_meaningful_content(&self, sm: &SourceMap) -> bool {
260        sm.span_to_snippet(self.span)
261            .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty())
262    }
263
264    fn trim_trivial_replacements(&mut self, sm: &SourceMap) {
267        if self.snippet.is_empty() {
268            return;
269        }
270        let Ok(snippet) = sm.span_to_snippet(self.span) else {
271            return;
272        };
273
274        if let Some((prefix, substr, suffix)) = as_substr(&snippet, &self.snippet) {
275            self.span = Span::new(
276                self.span.lo() + BytePos(prefix as u32),
277                self.span.hi() - BytePos(suffix as u32),
278                self.span.ctxt(),
279                self.span.parent(),
280            );
281            self.snippet = substr.to_string();
282        }
283    }
284}
285
286fn as_substr<'a>(original: &'a str, suggestion: &'a str) -> Option<(usize, &'a str, usize)> {
291    let common_prefix = original
292        .chars()
293        .zip(suggestion.chars())
294        .take_while(|(c1, c2)| c1 == c2)
295        .map(|(c, _)| c.len_utf8())
296        .sum();
297    let original = &original[common_prefix..];
298    let suggestion = &suggestion[common_prefix..];
299    if suggestion.ends_with(original) {
300        let common_suffix = original.len();
301        Some((common_prefix, &suggestion[..suggestion.len() - original.len()], common_suffix))
302    } else {
303        None
304    }
305}
306
307impl CodeSuggestion {
308    pub(crate) fn splice_lines(
311        &self,
312        sm: &SourceMap,
313    ) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, ConfusionType)> {
314        use rustc_span::{CharPos, Pos};
319
320        fn push_trailing(
329            buf: &mut String,
330            line_opt: Option<&Cow<'_, str>>,
331            lo: &Loc,
332            hi_opt: Option<&Loc>,
333        ) -> usize {
334            let mut line_count = 0;
335            let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
338            if let Some(line) = line_opt {
339                if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
340                    let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
342                    match hi_opt {
343                        Some(hi) if hi > lo => {
345                            line_count = line[lo..hi].matches('\n').count();
347                            buf.push_str(&line[lo..hi])
348                        }
349                        Some(_) => (),
350                        None => {
352                            line_count = line[lo..].matches('\n').count();
354                            buf.push_str(&line[lo..])
355                        }
356                    }
357                }
358                if hi_opt.is_none() {
360                    buf.push('\n');
361                }
362            }
363            line_count
364        }
365
366        assert!(!self.substitutions.is_empty());
367
368        self.substitutions
369            .iter()
370            .filter(|subst| {
371                let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
374                if invalid {
375                    debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
376                }
377                !invalid
378            })
379            .cloned()
380            .filter_map(|mut substitution| {
381                substitution.parts.sort_by_key(|part| part.span.lo());
384
385                let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
387                let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
388                let bounding_span = Span::with_root_ctxt(lo, hi);
389                let lines = sm.span_to_lines(bounding_span).ok()?;
391                assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
392
393                if !sm.ensure_source_file_source_present(&lines.file) {
395                    return None;
396                }
397
398                let mut highlights = vec![];
399                let sf = &lines.file;
409                let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
410                prev_hi.col = CharPos::from_usize(0);
411                let mut prev_line =
412                    lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
413                let mut buf = String::new();
414
415                let mut line_highlight = vec![];
416                let mut acc = 0;
419                let mut confusion_type = ConfusionType::None;
420                for part in &mut substitution.parts {
421                    part.trim_trivial_replacements(sm);
425
426                    let part_confusion = detect_confusion_type(sm, &part.snippet, part.span);
427                    confusion_type = confusion_type.combine(part_confusion);
428                    let cur_lo = sm.lookup_char_pos(part.span.lo());
429                    if prev_hi.line == cur_lo.line {
430                        let mut count =
431                            push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
432                        while count > 0 {
433                            highlights.push(std::mem::take(&mut line_highlight));
434                            acc = 0;
435                            count -= 1;
436                        }
437                    } else {
438                        acc = 0;
439                        highlights.push(std::mem::take(&mut line_highlight));
440                        let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
441                        while count > 0 {
442                            highlights.push(std::mem::take(&mut line_highlight));
443                            count -= 1;
444                        }
445                        for idx in prev_hi.line..(cur_lo.line - 1) {
447                            if let Some(line) = sf.get_line(idx) {
448                                buf.push_str(line.as_ref());
449                                buf.push('\n');
450                                highlights.push(std::mem::take(&mut line_highlight));
451                            }
452                        }
453                        if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
454                            let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
455                                Some((i, _)) => i,
456                                None => cur_line.len(),
457                            };
458                            buf.push_str(&cur_line[..end]);
459                        }
460                    }
461                    let len: isize = part
463                        .snippet
464                        .split('\n')
465                        .next()
466                        .unwrap_or(&part.snippet)
467                        .chars()
468                        .map(|c| match c {
469                            '\t' => 4,
470                            _ => 1,
471                        })
472                        .sum();
473                    if !is_different(sm, &part.snippet, part.span) {
474                        } else {
478                        line_highlight.push(SubstitutionHighlight {
479                            start: (cur_lo.col.0 as isize + acc) as usize,
480                            end: (cur_lo.col.0 as isize + acc + len) as usize,
481                        });
482                    }
483                    buf.push_str(&part.snippet);
484                    let cur_hi = sm.lookup_char_pos(part.span.hi());
485                    acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
490                    prev_hi = cur_hi;
491                    prev_line = sf.get_line(prev_hi.line - 1);
492                    for line in part.snippet.split('\n').skip(1) {
493                        acc = 0;
494                        highlights.push(std::mem::take(&mut line_highlight));
495                        let end: usize = line
496                            .chars()
497                            .map(|c| match c {
498                                '\t' => 4,
499                                _ => 1,
500                            })
501                            .sum();
502                        line_highlight.push(SubstitutionHighlight { start: 0, end });
503                    }
504                }
505                highlights.push(std::mem::take(&mut line_highlight));
506                if !buf.ends_with('\n') {
508                    push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
509                }
510                while buf.ends_with('\n') {
512                    buf.pop();
513                }
514                if highlights.iter().all(|parts| parts.is_empty()) {
515                    None
516                } else {
517                    Some((buf, substitution.parts, highlights, confusion_type))
518                }
519            })
520            .collect()
521    }
522}
523
524pub struct ExplicitBug;
527
528pub struct DelayedBugPanic;
531
532pub struct DiagCtxt {
536    inner: Lock<DiagCtxtInner>,
537}
538
539#[derive(Copy, Clone)]
540pub struct DiagCtxtHandle<'a> {
541    dcx: &'a DiagCtxt,
542    tainted_with_errors: Option<&'a Cell<Option<ErrorGuaranteed>>>,
545}
546
547impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
548    type Target = &'a DiagCtxt;
549
550    fn deref(&self) -> &Self::Target {
551        &self.dcx
552    }
553}
554
555struct DiagCtxtInner {
559    flags: DiagCtxtFlags,
560
561    registry: Registry,
562
563    err_guars: Vec<ErrorGuaranteed>,
565    lint_err_guars: Vec<ErrorGuaranteed>,
568    delayed_bugs: Vec<(DelayedDiagInner, ErrorGuaranteed)>,
570
571    deduplicated_err_count: usize,
573    deduplicated_warn_count: usize,
575
576    emitter: Box<DynEmitter>,
577
578    must_produce_diag: Option<Backtrace>,
581
582    has_printed: bool,
585
586    suppressed_expected_diag: bool,
589
590    taught_diagnostics: FxHashSet<ErrCode>,
594
595    emitted_diagnostic_codes: FxIndexSet<ErrCode>,
597
598    emitted_diagnostics: FxHashSet<Hash128>,
602
603    stashed_diagnostics:
609        FxIndexMap<StashKey, FxIndexMap<Span, (DiagInner, Option<ErrorGuaranteed>)>>,
610
611    future_breakage_diagnostics: Vec<DiagInner>,
612
613    fulfilled_expectations: FxIndexSet<LintExpectationId>,
625
626    ice_file: Option<PathBuf>,
629}
630
631#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
633pub enum StashKey {
634    ItemNoType,
635    UnderscoreForArrayLengths,
636    EarlySyntaxWarning,
637    CallIntoMethod,
638    LifetimeIsChar,
641    MaybeFruTypo,
644    CallAssocMethod,
645    AssociatedTypeSuggestion,
646    Cycle,
648    UndeterminedMacroResolution,
649    ExprInPat,
651    GenericInFieldExpr,
655}
656
657fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
658    (*f)(diag)
659}
660
661pub static TRACK_DIAGNOSTIC: AtomicRef<
664    fn(DiagInner, &mut dyn FnMut(DiagInner) -> Option<ErrorGuaranteed>) -> Option<ErrorGuaranteed>,
665> = AtomicRef::new(&(default_track_diagnostic as _));
666
667#[derive(Copy, Clone, Default)]
668pub struct DiagCtxtFlags {
669    pub can_emit_warnings: bool,
672    pub treat_err_as_bug: Option<NonZero<usize>>,
675    pub eagerly_emit_delayed_bugs: bool,
678    pub macro_backtrace: bool,
681    pub deduplicate_diagnostics: bool,
683    pub track_diagnostics: bool,
685}
686
687impl Drop for DiagCtxtInner {
688    fn drop(&mut self) {
689        self.emit_stashed_diagnostics();
697
698        self.flush_delayed();
702
703        if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
707            if let Some(backtrace) = &self.must_produce_diag {
708                let suggestion = match backtrace.status() {
709                    BacktraceStatus::Disabled => String::from(
710                        "Backtraces are currently disabled: set `RUST_BACKTRACE=1` and re-run \
711                        to see where it happened.",
712                    ),
713                    BacktraceStatus::Captured => format!(
714                        "This happened in the following `must_produce_diag` call's backtrace:\n\
715                        {backtrace}",
716                    ),
717                    _ => String::from("(impossible to capture backtrace where this happened)"),
718                };
719                panic!(
720                    "`trimmed_def_paths` called, diagnostics were expected but none were emitted. \
721                    Use `with_no_trimmed_paths` for debugging. {suggestion}"
722                );
723            }
724        }
725    }
726}
727
728impl DiagCtxt {
729    pub fn disable_warnings(mut self) -> Self {
730        self.inner.get_mut().flags.can_emit_warnings = false;
731        self
732    }
733
734    pub fn with_flags(mut self, flags: DiagCtxtFlags) -> Self {
735        self.inner.get_mut().flags = flags;
736        self
737    }
738
739    pub fn with_ice_file(mut self, ice_file: PathBuf) -> Self {
740        self.inner.get_mut().ice_file = Some(ice_file);
741        self
742    }
743
744    pub fn with_registry(mut self, registry: Registry) -> Self {
745        self.inner.get_mut().registry = registry;
746        self
747    }
748
749    pub fn new(emitter: Box<DynEmitter>) -> Self {
750        Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
751    }
752
753    pub fn make_silent(&self) {
754        let mut inner = self.inner.borrow_mut();
755        let translator = inner.emitter.translator().clone();
756        inner.emitter = Box::new(emitter::SilentEmitter { translator });
757    }
758
759    pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) {
760        self.inner.borrow_mut().emitter = emitter;
761    }
762
763    pub fn eagerly_translate<'a>(
765        &self,
766        message: DiagMessage,
767        args: impl Iterator<Item = DiagArg<'a>>,
768    ) -> SubdiagMessage {
769        let inner = self.inner.borrow();
770        inner.eagerly_translate(message, args)
771    }
772
773    pub fn eagerly_translate_to_string<'a>(
775        &self,
776        message: DiagMessage,
777        args: impl Iterator<Item = DiagArg<'a>>,
778    ) -> String {
779        let inner = self.inner.borrow();
780        inner.eagerly_translate_to_string(message, args)
781    }
782
783    pub fn can_emit_warnings(&self) -> bool {
787        self.inner.borrow_mut().flags.can_emit_warnings
788    }
789
790    pub fn reset_err_count(&self) {
796        let mut inner = self.inner.borrow_mut();
799        let DiagCtxtInner {
800            flags: _,
801            registry: _,
802            err_guars,
803            lint_err_guars,
804            delayed_bugs,
805            deduplicated_err_count,
806            deduplicated_warn_count,
807            emitter: _,
808            must_produce_diag,
809            has_printed,
810            suppressed_expected_diag,
811            taught_diagnostics,
812            emitted_diagnostic_codes,
813            emitted_diagnostics,
814            stashed_diagnostics,
815            future_breakage_diagnostics,
816            fulfilled_expectations,
817            ice_file: _,
818        } = inner.deref_mut();
819
820        *err_guars = Default::default();
823        *lint_err_guars = Default::default();
824        *delayed_bugs = Default::default();
825        *deduplicated_err_count = 0;
826        *deduplicated_warn_count = 0;
827        *must_produce_diag = None;
828        *has_printed = false;
829        *suppressed_expected_diag = false;
830        *taught_diagnostics = Default::default();
831        *emitted_diagnostic_codes = Default::default();
832        *emitted_diagnostics = Default::default();
833        *stashed_diagnostics = Default::default();
834        *future_breakage_diagnostics = Default::default();
835        *fulfilled_expectations = Default::default();
836    }
837
838    pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> {
839        DiagCtxtHandle { dcx: self, tainted_with_errors: None }
840    }
841
842    pub fn taintable_handle<'a>(
846        &'a self,
847        tainted_with_errors: &'a Cell<Option<ErrorGuaranteed>>,
848    ) -> DiagCtxtHandle<'a> {
849        DiagCtxtHandle { dcx: self, tainted_with_errors: Some(tainted_with_errors) }
850    }
851}
852
853impl<'a> DiagCtxtHandle<'a> {
854    pub fn stash_diagnostic(
876        &self,
877        span: Span,
878        key: StashKey,
879        diag: DiagInner,
880    ) -> Option<ErrorGuaranteed> {
881        let guar = match diag.level {
882            Bug | Fatal => {
883                self.span_bug(
884                    span,
885                    format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
886                );
887            }
888            Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
892            DelayedBug => {
893                return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors);
894            }
895            ForceWarning | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
896            | Expect => None,
897        };
898
899        self.inner
903            .borrow_mut()
904            .stashed_diagnostics
905            .entry(key)
906            .or_default()
907            .insert(span.with_parent(None), (diag, guar));
908
909        guar
910    }
911
912    pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
916        let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
918            |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
919        )?;
920        assert!(!diag.is_error());
921        assert!(guar.is_none());
922        Some(Diag::new_diagnostic(self, diag))
923    }
924
925    pub fn try_steal_modify_and_emit_err<F>(
930        self,
931        span: Span,
932        key: StashKey,
933        mut modify_err: F,
934    ) -> Option<ErrorGuaranteed>
935    where
936        F: FnMut(&mut Diag<'_>),
937    {
938        let err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
940            |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
941        );
942        err.map(|(err, guar)| {
943            assert_eq!(err.level, Error);
945            assert!(guar.is_some());
946            let mut err = Diag::<ErrorGuaranteed>::new_diagnostic(self, err);
947            modify_err(&mut err);
948            assert_eq!(err.level, Error);
949            err.emit()
950        })
951    }
952
953    pub fn try_steal_replace_and_emit_err(
957        self,
958        span: Span,
959        key: StashKey,
960        new_err: Diag<'_>,
961    ) -> ErrorGuaranteed {
962        let old_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        match old_err {
967            Some((old_err, guar)) => {
968                assert_eq!(old_err.level, Error);
969                assert!(guar.is_some());
970                Diag::<ErrorGuaranteed>::new_diagnostic(self, old_err).cancel();
973            }
974            None => {}
975        };
976        new_err.emit()
977    }
978
979    pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
980        let inner = self.inner.borrow();
981        if let Some(stashed_diagnostics) = inner.stashed_diagnostics.get(&key)
982            && !stashed_diagnostics.is_empty()
983        {
984            stashed_diagnostics.contains_key(&span.with_parent(None))
985        } else {
986            false
987        }
988    }
989
990    pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
992        self.inner.borrow_mut().emit_stashed_diagnostics()
993    }
994
995    #[inline]
997    pub fn err_count(&self) -> usize {
998        let inner = self.inner.borrow();
999        inner.err_guars.len()
1000            + inner.lint_err_guars.len()
1001            + inner
1002                .stashed_diagnostics
1003                .values()
1004                .map(|a| a.values().filter(|(_, guar)| guar.is_some()).count())
1005                .sum::<usize>()
1006    }
1007
1008    pub fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1011        self.inner.borrow().has_errors_excluding_lint_errors()
1012    }
1013
1014    pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
1016        self.inner.borrow().has_errors()
1017    }
1018
1019    pub fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1022        self.inner.borrow().has_errors_or_delayed_bugs()
1023    }
1024
1025    pub fn print_error_count(&self) {
1026        let mut inner = self.inner.borrow_mut();
1027
1028        assert!(inner.stashed_diagnostics.is_empty());
1031
1032        if inner.treat_err_as_bug() {
1033            return;
1034        }
1035
1036        let warnings = match inner.deduplicated_warn_count {
1037            0 => Cow::from(""),
1038            1 => Cow::from("1 warning emitted"),
1039            count => Cow::from(format!("{count} warnings emitted")),
1040        };
1041        let errors = match inner.deduplicated_err_count {
1042            0 => Cow::from(""),
1043            1 => Cow::from("aborting due to 1 previous error"),
1044            count => Cow::from(format!("aborting due to {count} previous errors")),
1045        };
1046
1047        match (errors.len(), warnings.len()) {
1048            (0, 0) => return,
1049            (0, _) => {
1050                inner.emit_diagnostic(
1053                    DiagInner::new(ForceWarning, DiagMessage::Str(warnings)),
1054                    None,
1055                );
1056            }
1057            (_, 0) => {
1058                inner.emit_diagnostic(DiagInner::new(Error, errors), self.tainted_with_errors);
1059            }
1060            (_, _) => {
1061                inner.emit_diagnostic(
1062                    DiagInner::new(Error, format!("{errors}; {warnings}")),
1063                    self.tainted_with_errors,
1064                );
1065            }
1066        }
1067
1068        let can_show_explain = inner.emitter.should_show_explain();
1069        let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty();
1070        if can_show_explain && are_there_diagnostics {
1071            let mut error_codes = inner
1072                .emitted_diagnostic_codes
1073                .iter()
1074                .filter_map(|&code| {
1075                    if inner.registry.try_find_description(code).is_ok() {
1076                        Some(code.to_string())
1077                    } else {
1078                        None
1079                    }
1080                })
1081                .collect::<Vec<_>>();
1082            if !error_codes.is_empty() {
1083                error_codes.sort();
1084                if error_codes.len() > 1 {
1085                    let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
1086                    let msg1 = format!(
1087                        "Some errors have detailed explanations: {}{}",
1088                        error_codes[..limit].join(", "),
1089                        if error_codes.len() > 9 { "..." } else { "." }
1090                    );
1091                    let msg2 = format!(
1092                        "For more information about an error, try `rustc --explain {}`.",
1093                        &error_codes[0]
1094                    );
1095                    inner.emit_diagnostic(DiagInner::new(FailureNote, msg1), None);
1096                    inner.emit_diagnostic(DiagInner::new(FailureNote, msg2), None);
1097                } else {
1098                    let msg = format!(
1099                        "For more information about this error, try `rustc --explain {}`.",
1100                        &error_codes[0]
1101                    );
1102                    inner.emit_diagnostic(DiagInner::new(FailureNote, msg), None);
1103                }
1104            }
1105        }
1106    }
1107
1108    pub fn abort_if_errors(&self) {
1113        if let Some(guar) = self.has_errors() {
1114            guar.raise_fatal();
1115        }
1116    }
1117
1118    pub fn must_teach(&self, code: ErrCode) -> bool {
1124        self.inner.borrow_mut().taught_diagnostics.insert(code)
1125    }
1126
1127    pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
1128        self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors)
1129    }
1130
1131    pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
1132        self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
1133    }
1134
1135    pub fn emit_timing_section_start(&self, record: TimingRecord) {
1136        self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::Start);
1137    }
1138
1139    pub fn emit_timing_section_end(&self, record: TimingRecord) {
1140        self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::End);
1141    }
1142
1143    pub fn emit_future_breakage_report(&self) {
1144        let inner = &mut *self.inner.borrow_mut();
1145        let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
1146        if !diags.is_empty() {
1147            inner.emitter.emit_future_breakage_report(diags, &inner.registry);
1148        }
1149    }
1150
1151    pub fn emit_unused_externs(
1152        &self,
1153        lint_level: rustc_lint_defs::Level,
1154        loud: bool,
1155        unused_externs: &[&str],
1156    ) {
1157        let mut inner = self.inner.borrow_mut();
1158
1159        if loud && lint_level.is_error() {
1170            #[allow(deprecated)]
1173            inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
1174            inner.panic_if_treat_err_as_bug();
1175        }
1176
1177        inner.emitter.emit_unused_externs(lint_level, unused_externs)
1178    }
1179
1180    #[must_use]
1183    pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
1184        std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
1185    }
1186
1187    pub fn flush_delayed(&self) {
1188        self.inner.borrow_mut().flush_delayed();
1189    }
1190
1191    #[track_caller]
1194    pub fn set_must_produce_diag(&self) {
1195        assert!(
1196            self.inner.borrow().must_produce_diag.is_none(),
1197            "should only need to collect a backtrace once"
1198        );
1199        self.inner.borrow_mut().must_produce_diag = Some(Backtrace::capture());
1200    }
1201}
1202
1203impl<'a> DiagCtxtHandle<'a> {
1208    #[track_caller]
1211    pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> {
1212        Diag::new(self, Bug, msg.into())
1213    }
1214
1215    #[track_caller]
1218    pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
1219        self.struct_bug(msg).emit()
1220    }
1221
1222    #[track_caller]
1225    pub fn struct_span_bug(
1226        self,
1227        span: impl Into<MultiSpan>,
1228        msg: impl Into<Cow<'static, str>>,
1229    ) -> Diag<'a, BugAbort> {
1230        self.struct_bug(msg).with_span(span)
1231    }
1232
1233    #[track_caller]
1236    pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
1237        self.struct_span_bug(span, msg.into()).emit()
1238    }
1239
1240    #[track_caller]
1241    pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> {
1242        bug.into_diag(self, Bug)
1243    }
1244
1245    #[track_caller]
1246    pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! {
1247        self.create_bug(bug).emit()
1248    }
1249
1250    #[rustc_lint_diagnostics]
1251    #[track_caller]
1252    pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> {
1253        Diag::new(self, Fatal, msg)
1254    }
1255
1256    #[rustc_lint_diagnostics]
1257    #[track_caller]
1258    pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
1259        self.struct_fatal(msg).emit()
1260    }
1261
1262    #[rustc_lint_diagnostics]
1263    #[track_caller]
1264    pub fn struct_span_fatal(
1265        self,
1266        span: impl Into<MultiSpan>,
1267        msg: impl Into<DiagMessage>,
1268    ) -> Diag<'a, FatalAbort> {
1269        self.struct_fatal(msg).with_span(span)
1270    }
1271
1272    #[rustc_lint_diagnostics]
1273    #[track_caller]
1274    pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
1275        self.struct_span_fatal(span, msg).emit()
1276    }
1277
1278    #[track_caller]
1279    pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> {
1280        fatal.into_diag(self, Fatal)
1281    }
1282
1283    #[track_caller]
1284    pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
1285        self.create_fatal(fatal).emit()
1286    }
1287
1288    #[track_caller]
1289    pub fn create_almost_fatal(
1290        self,
1291        fatal: impl Diagnostic<'a, FatalError>,
1292    ) -> Diag<'a, FatalError> {
1293        fatal.into_diag(self, Fatal)
1294    }
1295
1296    #[track_caller]
1297    pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError {
1298        self.create_almost_fatal(fatal).emit()
1299    }
1300
1301    #[rustc_lint_diagnostics]
1303    #[track_caller]
1304    pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> {
1305        Diag::new(self, Error, msg)
1306    }
1307
1308    #[rustc_lint_diagnostics]
1309    #[track_caller]
1310    pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
1311        self.struct_err(msg).emit()
1312    }
1313
1314    #[rustc_lint_diagnostics]
1315    #[track_caller]
1316    pub fn struct_span_err(
1317        self,
1318        span: impl Into<MultiSpan>,
1319        msg: impl Into<DiagMessage>,
1320    ) -> Diag<'a> {
1321        self.struct_err(msg).with_span(span)
1322    }
1323
1324    #[rustc_lint_diagnostics]
1325    #[track_caller]
1326    pub fn span_err(
1327        self,
1328        span: impl Into<MultiSpan>,
1329        msg: impl Into<DiagMessage>,
1330    ) -> ErrorGuaranteed {
1331        self.struct_span_err(span, msg).emit()
1332    }
1333
1334    #[track_caller]
1335    pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> {
1336        err.into_diag(self, Error)
1337    }
1338
1339    #[track_caller]
1340    pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
1341        self.create_err(err).emit()
1342    }
1343
1344    #[track_caller]
1349    pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
1350        Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
1351    }
1352
1353    #[track_caller]
1361    pub fn span_delayed_bug(
1362        self,
1363        sp: impl Into<MultiSpan>,
1364        msg: impl Into<Cow<'static, str>>,
1365    ) -> ErrorGuaranteed {
1366        Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
1367    }
1368
1369    #[rustc_lint_diagnostics]
1370    #[track_caller]
1371    pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1372        Diag::new(self, Warning, msg)
1373    }
1374
1375    #[rustc_lint_diagnostics]
1376    #[track_caller]
1377    pub fn warn(self, msg: impl Into<DiagMessage>) {
1378        self.struct_warn(msg).emit()
1379    }
1380
1381    #[rustc_lint_diagnostics]
1382    #[track_caller]
1383    pub fn struct_span_warn(
1384        self,
1385        span: impl Into<MultiSpan>,
1386        msg: impl Into<DiagMessage>,
1387    ) -> Diag<'a, ()> {
1388        self.struct_warn(msg).with_span(span)
1389    }
1390
1391    #[rustc_lint_diagnostics]
1392    #[track_caller]
1393    pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1394        self.struct_span_warn(span, msg).emit()
1395    }
1396
1397    #[track_caller]
1398    pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1399        warning.into_diag(self, Warning)
1400    }
1401
1402    #[track_caller]
1403    pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) {
1404        self.create_warn(warning).emit()
1405    }
1406
1407    #[rustc_lint_diagnostics]
1408    #[track_caller]
1409    pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1410        Diag::new(self, Note, msg)
1411    }
1412
1413    #[rustc_lint_diagnostics]
1414    #[track_caller]
1415    pub fn note(&self, msg: impl Into<DiagMessage>) {
1416        self.struct_note(msg).emit()
1417    }
1418
1419    #[rustc_lint_diagnostics]
1420    #[track_caller]
1421    pub fn struct_span_note(
1422        self,
1423        span: impl Into<MultiSpan>,
1424        msg: impl Into<DiagMessage>,
1425    ) -> Diag<'a, ()> {
1426        self.struct_note(msg).with_span(span)
1427    }
1428
1429    #[rustc_lint_diagnostics]
1430    #[track_caller]
1431    pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1432        self.struct_span_note(span, msg).emit()
1433    }
1434
1435    #[track_caller]
1436    pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1437        note.into_diag(self, Note)
1438    }
1439
1440    #[track_caller]
1441    pub fn emit_note(self, note: impl Diagnostic<'a, ()>) {
1442        self.create_note(note).emit()
1443    }
1444
1445    #[rustc_lint_diagnostics]
1446    #[track_caller]
1447    pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1448        Diag::new(self, Help, msg)
1449    }
1450
1451    #[rustc_lint_diagnostics]
1452    #[track_caller]
1453    pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1454        Diag::new(self, FailureNote, msg)
1455    }
1456
1457    #[rustc_lint_diagnostics]
1458    #[track_caller]
1459    pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1460        Diag::new(self, Allow, msg)
1461    }
1462
1463    #[rustc_lint_diagnostics]
1464    #[track_caller]
1465    pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> {
1466        Diag::new(self, Expect, msg).with_lint_id(id)
1467    }
1468}
1469
1470impl DiagCtxtInner {
1475    fn new(emitter: Box<DynEmitter>) -> Self {
1476        Self {
1477            flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
1478            registry: Registry::new(&[]),
1479            err_guars: Vec::new(),
1480            lint_err_guars: Vec::new(),
1481            delayed_bugs: Vec::new(),
1482            deduplicated_err_count: 0,
1483            deduplicated_warn_count: 0,
1484            emitter,
1485            must_produce_diag: None,
1486            has_printed: false,
1487            suppressed_expected_diag: false,
1488            taught_diagnostics: Default::default(),
1489            emitted_diagnostic_codes: Default::default(),
1490            emitted_diagnostics: Default::default(),
1491            stashed_diagnostics: Default::default(),
1492            future_breakage_diagnostics: Vec::new(),
1493            fulfilled_expectations: Default::default(),
1494            ice_file: None,
1495        }
1496    }
1497
1498    fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
1500        let mut guar = None;
1501        let has_errors = !self.err_guars.is_empty();
1502        for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
1503            for (_, (diag, _guar)) in stashed_diagnostics {
1504                if !diag.is_error() {
1505                    if !diag.is_force_warn() && has_errors {
1509                        continue;
1510                    }
1511                }
1512                guar = guar.or(self.emit_diagnostic(diag, None));
1513            }
1514        }
1515        guar
1516    }
1517
1518    fn emit_diagnostic(
1520        &mut self,
1521        mut diagnostic: DiagInner,
1522        taint: Option<&Cell<Option<ErrorGuaranteed>>>,
1523    ) -> Option<ErrorGuaranteed> {
1524        if diagnostic.has_future_breakage() {
1525            assert_matches!(diagnostic.level, Error | ForceWarning | Warning | Allow | Expect);
1529            self.future_breakage_diagnostics.push(diagnostic.clone());
1530        }
1531
1532        match diagnostic.level {
1536            Bug => {}
1537            Fatal | Error => {
1538                if self.treat_next_err_as_bug() {
1539                    diagnostic.level = Bug;
1541                }
1542            }
1543            DelayedBug => {
1544                if self.flags.eagerly_emit_delayed_bugs {
1549                    if self.treat_next_err_as_bug() {
1551                        diagnostic.level = Bug;
1552                    } else {
1553                        diagnostic.level = Error;
1554                    }
1555                } else {
1556                    return if let Some(guar) = self.has_errors() {
1559                        Some(guar)
1560                    } else {
1561                        let backtrace = std::backtrace::Backtrace::capture();
1565                        #[allow(deprecated)]
1569                        let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1570                        self.delayed_bugs
1571                            .push((DelayedDiagInner::with_backtrace(diagnostic, backtrace), guar));
1572                        Some(guar)
1573                    };
1574                }
1575            }
1576            ForceWarning if diagnostic.lint_id.is_none() => {} Warning => {
1578                if !self.flags.can_emit_warnings {
1579                    if diagnostic.has_future_breakage() {
1581                        TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1583                    }
1584                    return None;
1585                }
1586            }
1587            Note | Help | FailureNote => {}
1588            OnceNote | OnceHelp => panic!("bad level: {:?}", diagnostic.level),
1589            Allow => {
1590                if diagnostic.has_future_breakage() {
1592                    TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1594                    self.suppressed_expected_diag = true;
1595                }
1596                return None;
1597            }
1598            Expect | ForceWarning => {
1599                self.fulfilled_expectations.insert(diagnostic.lint_id.unwrap());
1600                if let Expect = diagnostic.level {
1601                    TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1603                    self.suppressed_expected_diag = true;
1604                    return None;
1605                }
1606            }
1607        }
1608
1609        TRACK_DIAGNOSTIC(diagnostic, &mut |mut diagnostic| {
1610            if let Some(code) = diagnostic.code {
1611                self.emitted_diagnostic_codes.insert(code);
1612            }
1613
1614            let already_emitted = {
1615                let mut hasher = StableHasher::new();
1616                diagnostic.hash(&mut hasher);
1617                let diagnostic_hash = hasher.finish();
1618                !self.emitted_diagnostics.insert(diagnostic_hash)
1619            };
1620
1621            let is_error = diagnostic.is_error();
1622            let is_lint = diagnostic.is_lint.is_some();
1623
1624            if !(self.flags.deduplicate_diagnostics && already_emitted) {
1627                debug!(?diagnostic);
1628                debug!(?self.emitted_diagnostics);
1629
1630                let not_yet_emitted = |sub: &mut Subdiag| {
1631                    debug!(?sub);
1632                    if sub.level != OnceNote && sub.level != OnceHelp {
1633                        return true;
1634                    }
1635                    let mut hasher = StableHasher::new();
1636                    sub.hash(&mut hasher);
1637                    let diagnostic_hash = hasher.finish();
1638                    debug!(?diagnostic_hash);
1639                    self.emitted_diagnostics.insert(diagnostic_hash)
1640                };
1641                diagnostic.children.retain_mut(not_yet_emitted);
1642                if already_emitted {
1643                    let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`";
1644                    diagnostic.sub(Note, msg, MultiSpan::new());
1645                }
1646
1647                if is_error {
1648                    self.deduplicated_err_count += 1;
1649                } else if matches!(diagnostic.level, ForceWarning | Warning) {
1650                    self.deduplicated_warn_count += 1;
1651                }
1652                self.has_printed = true;
1653
1654                self.emitter.emit_diagnostic(diagnostic, &self.registry);
1655            }
1656
1657            if is_error {
1658                if !self.delayed_bugs.is_empty() {
1663                    assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0);
1664                    self.delayed_bugs.clear();
1665                    self.delayed_bugs.shrink_to_fit();
1666                }
1667
1668                #[allow(deprecated)]
1671                let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1672                if is_lint {
1673                    self.lint_err_guars.push(guar);
1674                } else {
1675                    if let Some(taint) = taint {
1676                        taint.set(Some(guar));
1677                    }
1678                    self.err_guars.push(guar);
1679                }
1680                self.panic_if_treat_err_as_bug();
1681                Some(guar)
1682            } else {
1683                None
1684            }
1685        })
1686    }
1687
1688    fn treat_err_as_bug(&self) -> bool {
1689        self.flags
1690            .treat_err_as_bug
1691            .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
1692    }
1693
1694    fn treat_next_err_as_bug(&self) -> bool {
1696        self.flags
1697            .treat_err_as_bug
1698            .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
1699    }
1700
1701    fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1702        self.err_guars.get(0).copied().or_else(|| {
1703            if let Some((_diag, guar)) = self
1704                .stashed_diagnostics
1705                .values()
1706                .flat_map(|stashed_diagnostics| stashed_diagnostics.values())
1707                .find(|(diag, guar)| guar.is_some() && diag.is_lint.is_none())
1708            {
1709                *guar
1710            } else {
1711                None
1712            }
1713        })
1714    }
1715
1716    fn has_errors(&self) -> Option<ErrorGuaranteed> {
1717        self.err_guars.get(0).copied().or_else(|| self.lint_err_guars.get(0).copied()).or_else(
1718            || {
1719                self.stashed_diagnostics.values().find_map(|stashed_diagnostics| {
1720                    stashed_diagnostics.values().find_map(|(_, guar)| *guar)
1721                })
1722            },
1723        )
1724    }
1725
1726    fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1727        self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
1728    }
1729
1730    fn eagerly_translate<'a>(
1732        &self,
1733        message: DiagMessage,
1734        args: impl Iterator<Item = DiagArg<'a>>,
1735    ) -> SubdiagMessage {
1736        SubdiagMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
1737    }
1738
1739    fn eagerly_translate_to_string<'a>(
1741        &self,
1742        message: DiagMessage,
1743        args: impl Iterator<Item = DiagArg<'a>>,
1744    ) -> String {
1745        let args = crate::translation::to_fluent_args(args);
1746        self.emitter
1747            .translator()
1748            .translate_message(&message, &args)
1749            .map_err(Report::new)
1750            .unwrap()
1751            .to_string()
1752    }
1753
1754    fn eagerly_translate_for_subdiag(
1755        &self,
1756        diag: &DiagInner,
1757        msg: impl Into<SubdiagMessage>,
1758    ) -> SubdiagMessage {
1759        let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
1760        self.eagerly_translate(msg, diag.args.iter())
1761    }
1762
1763    fn flush_delayed(&mut self) {
1764        assert!(self.stashed_diagnostics.is_empty());
1768
1769        if !self.err_guars.is_empty() {
1770            return;
1772        }
1773
1774        if self.delayed_bugs.is_empty() {
1775            return;
1777        }
1778
1779        let bugs: Vec<_> =
1780            std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
1781
1782        let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0"));
1783        let decorate = backtrace || self.ice_file.is_none();
1784        let mut out = self
1785            .ice_file
1786            .as_ref()
1787            .and_then(|file| std::fs::File::options().create(true).append(true).open(file).ok());
1788
1789        let note1 = "no errors encountered even though delayed bugs were created";
1794        let note2 = "those delayed bugs will now be shown as internal compiler errors";
1795        self.emit_diagnostic(DiagInner::new(Note, note1), None);
1796        self.emit_diagnostic(DiagInner::new(Note, note2), None);
1797
1798        for bug in bugs {
1799            if let Some(out) = &mut out {
1800                _ = write!(
1801                    out,
1802                    "delayed bug: {}\n{}\n",
1803                    bug.inner
1804                        .messages
1805                        .iter()
1806                        .filter_map(|(msg, _)| msg.as_str())
1807                        .collect::<String>(),
1808                    &bug.note
1809                );
1810            }
1811
1812            let mut bug = if decorate { bug.decorate(self) } else { bug.inner };
1813
1814            if bug.level != DelayedBug {
1816                bug.arg("level", bug.level);
1823                let msg = crate::fluent_generated::errors_invalid_flushed_delayed_diagnostic_level;
1824                let msg = self.eagerly_translate_for_subdiag(&bug, msg); bug.sub(Note, msg, bug.span.primary_span().unwrap().into());
1826            }
1827            bug.level = Bug;
1828
1829            self.emit_diagnostic(bug, None);
1830        }
1831
1832        panic::panic_any(DelayedBugPanic);
1834    }
1835
1836    fn panic_if_treat_err_as_bug(&self) {
1837        if self.treat_err_as_bug() {
1838            let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
1839            assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
1840            if n == 1 {
1841                panic!("aborting due to `-Z treat-err-as-bug=1`");
1842            } else {
1843                panic!("aborting after {n} errors due to `-Z treat-err-as-bug={n}`");
1844            }
1845        }
1846    }
1847}
1848
1849struct DelayedDiagInner {
1850    inner: DiagInner,
1851    note: Backtrace,
1852}
1853
1854impl DelayedDiagInner {
1855    fn with_backtrace(diagnostic: DiagInner, backtrace: Backtrace) -> Self {
1856        DelayedDiagInner { inner: diagnostic, note: backtrace }
1857    }
1858
1859    fn decorate(self, dcx: &DiagCtxtInner) -> DiagInner {
1860        let mut diag = self.inner;
1864        let msg = match self.note.status() {
1865            BacktraceStatus::Captured => crate::fluent_generated::errors_delayed_at_with_newline,
1866            _ => crate::fluent_generated::errors_delayed_at_without_newline,
1869        };
1870        diag.arg("emitted_at", diag.emitted_at.clone());
1871        diag.arg("note", self.note);
1872        let msg = dcx.eagerly_translate_for_subdiag(&diag, msg); diag.sub(Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into());
1874        diag
1875    }
1876}
1877
1878#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
1898pub enum Level {
1899    Bug,
1901
1902    Fatal,
1905
1906    Error,
1909
1910    DelayedBug,
1915
1916    ForceWarning,
1922
1923    Warning,
1926
1927    Note,
1929
1930    OnceNote,
1932
1933    Help,
1935
1936    OnceHelp,
1938
1939    FailureNote,
1942
1943    Allow,
1945
1946    Expect,
1948}
1949
1950impl fmt::Display for Level {
1951    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1952        self.to_str().fmt(f)
1953    }
1954}
1955
1956impl Level {
1957    fn color(self) -> ColorSpec {
1958        let mut spec = ColorSpec::new();
1959        match self {
1960            Bug | Fatal | Error | DelayedBug => {
1961                spec.set_fg(Some(Color::Red)).set_intense(true);
1962            }
1963            ForceWarning | Warning => {
1964                spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
1965            }
1966            Note | OnceNote => {
1967                spec.set_fg(Some(Color::Green)).set_intense(true);
1968            }
1969            Help | OnceHelp => {
1970                spec.set_fg(Some(Color::Cyan)).set_intense(true);
1971            }
1972            FailureNote => {}
1973            Allow | Expect => unreachable!(),
1974        }
1975        spec
1976    }
1977
1978    pub fn to_str(self) -> &'static str {
1979        match self {
1980            Bug | DelayedBug => "error: internal compiler error",
1981            Fatal | Error => "error",
1982            ForceWarning | Warning => "warning",
1983            Note | OnceNote => "note",
1984            Help | OnceHelp => "help",
1985            FailureNote => "failure-note",
1986            Allow | Expect => unreachable!(),
1987        }
1988    }
1989
1990    pub fn is_failure_note(&self) -> bool {
1991        matches!(*self, FailureNote)
1992    }
1993
1994    fn can_be_subdiag(&self) -> bool {
1996        match self {
1997            Bug | DelayedBug | Fatal | Error | ForceWarning | FailureNote | Allow | Expect => false,
1998
1999            Warning | Note | Help | OnceNote | OnceHelp => true,
2000        }
2001    }
2002}
2003
2004impl IntoDiagArg for Level {
2005    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
2006        DiagArgValue::Str(Cow::from(self.to_string()))
2007    }
2008}
2009
2010pub fn elided_lifetime_in_path_suggestion(
2012    source_map: &SourceMap,
2013    n: usize,
2014    path_span: Span,
2015    incl_angl_brckt: bool,
2016    insertion_span: Span,
2017) -> ElidedLifetimeInPathSubdiag {
2018    let expected = ExpectedLifetimeParameter { span: path_span, count: n };
2019    let indicate = source_map.is_span_accessible(insertion_span).then(|| {
2021        let anon_lts = vec!["'_"; n].join(", ");
2022        let suggestion =
2023            if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
2024
2025        IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
2026    });
2027
2028    ElidedLifetimeInPathSubdiag { expected, indicate }
2029}
2030
2031pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
2032    diag: &mut Diag<'a, G>,
2033    ambiguity: rustc_lint_defs::AmbiguityErrorDiag,
2034) {
2035    diag.span_label(ambiguity.label_span, ambiguity.label_msg);
2036    diag.note(ambiguity.note_msg);
2037    diag.span_note(ambiguity.b1_span, ambiguity.b1_note_msg);
2038    for help_msg in ambiguity.b1_help_msgs {
2039        diag.help(help_msg);
2040    }
2041    diag.span_note(ambiguity.b2_span, ambiguity.b2_note_msg);
2042    for help_msg in ambiguity.b2_help_msgs {
2043        diag.help(help_msg);
2044    }
2045}
2046
2047pub fn a_or_an(s: &str) -> &'static str {
2051    let mut chars = s.chars();
2052    let Some(mut first_alpha_char) = chars.next() else {
2053        return "a";
2054    };
2055    if first_alpha_char == '`' {
2056        let Some(next) = chars.next() else {
2057            return "a";
2058        };
2059        first_alpha_char = next;
2060    }
2061    if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
2062        "an"
2063    } else {
2064        "a"
2065    }
2066}
2067
2068#[derive(Clone, Copy, PartialEq, Hash, Debug)]
2069pub enum TerminalUrl {
2070    No,
2071    Yes,
2072    Auto,
2073}