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#![cfg_attr(bootstrap, feature(array_windows))]
11#![feature(assert_matches)]
12#![feature(associated_type_defaults)]
13#![feature(box_patterns)]
14#![feature(default_field_values)]
15#![feature(error_reporter)]
16#![feature(macro_metavar_expr_concat)]
17#![feature(negative_impls)]
18#![feature(never_type)]
19#![feature(rustc_attrs)]
20#![feature(try_blocks)]
21#![feature(yeet_expr)]
22extern crate self as rustc_errors;
25
26use std::assert_matches::assert_matches;
27use std::backtrace::{Backtrace, BacktraceStatus};
28use std::borrow::Cow;
29use std::cell::Cell;
30use std::error::Report;
31use std::ffi::OsStr;
32use std::hash::Hash;
33use std::io::Write;
34use std::num::NonZero;
35use std::ops::DerefMut;
36use std::path::{Path, PathBuf};
37use std::{fmt, panic};
38
39use Level::*;
40pub use anstream::{AutoStream, ColorChoice};
43pub use anstyle::{
44 Ansi256Color, AnsiColor, Color, EffectIter, Effects, Reset, RgbColor, Style as Anstyle,
45};
46pub use codes::*;
47pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
48pub use diagnostic::{
49 BugAbort, Diag, DiagArgMap, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee,
50 FatalAbort, LintDiagnostic, LintDiagnosticBox, StringPart, Subdiag, Subdiagnostic,
51};
52pub use diagnostic_impls::{
53 DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
54 IndicateAnonymousLifetime, SingleLabelManySpans,
55};
56pub use emitter::ColorConfig;
57use emitter::{ConfusionType, DynEmitter, Emitter, detect_confusion_type, is_different};
58use rustc_data_structures::AtomicRef;
59use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
60use rustc_data_structures::stable_hasher::StableHasher;
61use rustc_data_structures::sync::{DynSend, Lock};
62pub use rustc_error_messages::{
63 DiagArg, DiagArgFromDisplay, DiagArgName, DiagArgValue, DiagMessage, FluentBundle, IntoDiagArg,
64 LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage,
65 fallback_fluent_bundle, fluent_bundle, into_diag_arg_using_display,
66};
67use rustc_hashes::Hash128;
68use rustc_lint_defs::LintExpectationId;
69pub use rustc_lint_defs::{Applicability, listify, pluralize};
70use rustc_macros::{Decodable, Encodable};
71pub use rustc_span::ErrorGuaranteed;
72pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
73use rustc_span::source_map::SourceMap;
74use rustc_span::{BytePos, DUMMY_SP, Loc, Span};
75pub use snippet::Style;
76use tracing::debug;
77
78use crate::emitter::TimingEvent;
79use crate::registry::Registry;
80use crate::timings::TimingRecord;
81
82pub mod annotate_snippet_emitter_writer;
83pub mod codes;
84mod decorate_diag;
85mod diagnostic;
86mod diagnostic_impls;
87pub mod emitter;
88pub mod error;
89pub mod json;
90mod lock;
91pub mod markdown;
92pub mod registry;
93mod snippet;
94mod styled_buffer;
95#[cfg(test)]
96mod tests;
97pub mod timings;
98pub mod translation;
99
100pub type PResult<'a, T> = Result<T, Diag<'a>>;
101
102rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
103
104#[cfg(target_pointer_width = "64")]
106rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24);
107#[cfg(target_pointer_width = "64")]
108rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24);
109
110#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
111pub enum SuggestionStyle {
112 HideCodeInline,
114 HideCodeAlways,
116 CompletelyHidden,
118 ShowCode,
122 ShowAlways,
124}
125
126impl SuggestionStyle {
127 fn hide_inline(&self) -> bool {
128 !matches!(*self, SuggestionStyle::ShowCode)
129 }
130}
131
132#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
134pub enum Suggestions {
135 Enabled(Vec<CodeSuggestion>),
140 Sealed(Box<[CodeSuggestion]>),
144 Disabled,
148}
149
150impl Suggestions {
151 pub fn unwrap_tag(self) -> Vec<CodeSuggestion> {
153 match self {
154 Suggestions::Enabled(suggestions) => suggestions,
155 Suggestions::Sealed(suggestions) => suggestions.into_vec(),
156 Suggestions::Disabled => Vec::new(),
157 }
158 }
159}
160
161impl Default for Suggestions {
162 fn default() -> Self {
163 Self::Enabled(vec![])
164 }
165}
166
167#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
168pub struct CodeSuggestion {
169 pub substitutions: Vec<Substitution>,
191 pub msg: DiagMessage,
192 pub style: SuggestionStyle,
194 pub applicability: Applicability,
200}
201
202#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
203pub struct Substitution {
205 pub parts: Vec<SubstitutionPart>,
206}
207
208#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
209pub struct SubstitutionPart {
210 pub span: Span,
211 pub snippet: String,
212}
213
214#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
215pub struct TrimmedSubstitutionPart {
216 pub original_span: Span,
217 pub span: Span,
218 pub snippet: String,
219}
220
221#[derive(Debug, Clone, Copy)]
224pub(crate) struct SubstitutionHighlight {
225 start: usize,
226 end: usize,
227}
228
229impl SubstitutionPart {
230 fn trim_trivial_replacements(self, sm: &SourceMap) -> TrimmedSubstitutionPart {
233 let mut trimmed_part = TrimmedSubstitutionPart {
234 original_span: self.span,
235 span: self.span,
236 snippet: self.snippet,
237 };
238 if trimmed_part.snippet.is_empty() {
239 return trimmed_part;
240 }
241 let Ok(snippet) = sm.span_to_snippet(trimmed_part.span) else {
242 return trimmed_part;
243 };
244
245 if let Some((prefix, substr, suffix)) = as_substr(&snippet, &trimmed_part.snippet) {
246 trimmed_part.span = Span::new(
247 trimmed_part.span.lo() + BytePos(prefix as u32),
248 trimmed_part.span.hi() - BytePos(suffix as u32),
249 trimmed_part.span.ctxt(),
250 trimmed_part.span.parent(),
251 );
252 trimmed_part.snippet = substr.to_string();
253 }
254 trimmed_part
255 }
256}
257
258impl TrimmedSubstitutionPart {
259 pub fn is_addition(&self, sm: &SourceMap) -> bool {
260 !self.snippet.is_empty() && !self.replaces_meaningful_content(sm)
261 }
262
263 pub fn is_deletion(&self, sm: &SourceMap) -> bool {
264 self.snippet.trim().is_empty() && self.replaces_meaningful_content(sm)
265 }
266
267 pub fn is_replacement(&self, sm: &SourceMap) -> bool {
268 !self.snippet.is_empty() && self.replaces_meaningful_content(sm)
269 }
270
271 pub fn is_destructive_replacement(&self, sm: &SourceMap) -> bool {
276 self.is_replacement(sm)
277 && !sm
278 .span_to_snippet(self.span)
279 .is_ok_and(|snippet| as_substr(snippet.trim(), self.snippet.trim()).is_some())
280 }
281
282 fn replaces_meaningful_content(&self, sm: &SourceMap) -> bool {
283 sm.span_to_snippet(self.span)
284 .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty())
285 }
286}
287
288fn as_substr<'a>(original: &'a str, suggestion: &'a str) -> Option<(usize, &'a str, usize)> {
293 let common_prefix = original
294 .chars()
295 .zip(suggestion.chars())
296 .take_while(|(c1, c2)| c1 == c2)
297 .map(|(c, _)| c.len_utf8())
298 .sum();
299 let original = &original[common_prefix..];
300 let suggestion = &suggestion[common_prefix..];
301 if suggestion.ends_with(original) {
302 let common_suffix = original.len();
303 Some((common_prefix, &suggestion[..suggestion.len() - original.len()], common_suffix))
304 } else {
305 None
306 }
307}
308
309impl CodeSuggestion {
310 pub(crate) fn splice_lines(
313 &self,
314 sm: &SourceMap,
315 ) -> Vec<(String, Vec<TrimmedSubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, ConfusionType)>
316 {
317 use rustc_span::{CharPos, Pos};
322
323 fn push_trailing(
332 buf: &mut String,
333 line_opt: Option<&Cow<'_, str>>,
334 lo: &Loc,
335 hi_opt: Option<&Loc>,
336 ) -> usize {
337 let mut line_count = 0;
338 let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
341 if let Some(line) = line_opt {
342 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
343 let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
345 match hi_opt {
346 Some(hi) if hi > lo => {
348 line_count = line[lo..hi].matches('\n').count();
350 buf.push_str(&line[lo..hi])
351 }
352 Some(_) => (),
353 None => {
355 line_count = line[lo..].matches('\n').count();
357 buf.push_str(&line[lo..])
358 }
359 }
360 }
361 if hi_opt.is_none() {
363 buf.push('\n');
364 }
365 }
366 line_count
367 }
368
369 assert!(!self.substitutions.is_empty());
370
371 self.substitutions
372 .iter()
373 .filter(|subst| {
374 let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
377 if invalid {
378 debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
379 }
380 !invalid
381 })
382 .cloned()
383 .filter_map(|mut substitution| {
384 substitution.parts.sort_by_key(|part| part.span.lo());
387
388 let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
390 let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
391 let bounding_span = Span::with_root_ctxt(lo, hi);
392 let lines = sm.span_to_lines(bounding_span).ok()?;
394 assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
395
396 if !sm.ensure_source_file_source_present(&lines.file) {
398 return None;
399 }
400
401 let mut highlights = vec![];
402 let sf = &lines.file;
412 let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
413 prev_hi.col = CharPos::from_usize(0);
414 let mut prev_line =
415 lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
416 let mut buf = String::new();
417
418 let mut line_highlight = vec![];
419 let mut acc = 0;
422 let mut confusion_type = ConfusionType::None;
423
424 let trimmed_parts = substitution
425 .parts
426 .into_iter()
427 .map(|part| part.trim_trivial_replacements(sm))
431 .collect::<Vec<_>>();
432
433 for part in &trimmed_parts {
434 let part_confusion = detect_confusion_type(sm, &part.snippet, part.span);
435 confusion_type = confusion_type.combine(part_confusion);
436 let cur_lo = sm.lookup_char_pos(part.span.lo());
437 if prev_hi.line == cur_lo.line {
438 let mut count =
439 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
440 while count > 0 {
441 highlights.push(std::mem::take(&mut line_highlight));
442 acc = 0;
443 count -= 1;
444 }
445 } else {
446 acc = 0;
447 highlights.push(std::mem::take(&mut line_highlight));
448 let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
449 while count > 0 {
450 highlights.push(std::mem::take(&mut line_highlight));
451 count -= 1;
452 }
453 for idx in prev_hi.line..(cur_lo.line - 1) {
455 if let Some(line) = sf.get_line(idx) {
456 buf.push_str(line.as_ref());
457 buf.push('\n');
458 highlights.push(std::mem::take(&mut line_highlight));
459 }
460 }
461 if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
462 let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
463 Some((i, _)) => i,
464 None => cur_line.len(),
465 };
466 buf.push_str(&cur_line[..end]);
467 }
468 }
469 let len: isize = part
471 .snippet
472 .split('\n')
473 .next()
474 .unwrap_or(&part.snippet)
475 .chars()
476 .map(|c| match c {
477 '\t' => 4,
478 _ => 1,
479 })
480 .sum();
481 if !is_different(sm, &part.snippet, part.span) {
482 } else {
486 line_highlight.push(SubstitutionHighlight {
487 start: (cur_lo.col.0 as isize + acc) as usize,
488 end: (cur_lo.col.0 as isize + acc + len) as usize,
489 });
490 }
491 buf.push_str(&part.snippet);
492 let cur_hi = sm.lookup_char_pos(part.span.hi());
493 acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
498 prev_hi = cur_hi;
499 prev_line = sf.get_line(prev_hi.line - 1);
500 for line in part.snippet.split('\n').skip(1) {
501 acc = 0;
502 highlights.push(std::mem::take(&mut line_highlight));
503 let end: usize = line
504 .chars()
505 .map(|c| match c {
506 '\t' => 4,
507 _ => 1,
508 })
509 .sum();
510 line_highlight.push(SubstitutionHighlight { start: 0, end });
511 }
512 }
513 highlights.push(std::mem::take(&mut line_highlight));
514 if !buf.ends_with('\n') {
516 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
517 }
518 while buf.ends_with('\n') {
520 buf.pop();
521 }
522 if highlights.iter().all(|parts| parts.is_empty()) {
523 None
524 } else {
525 Some((buf, trimmed_parts, highlights, confusion_type))
526 }
527 })
528 .collect()
529 }
530}
531
532pub struct ExplicitBug;
535
536pub struct DelayedBugPanic;
539
540pub struct DiagCtxt {
544 inner: Lock<DiagCtxtInner>,
545}
546
547#[derive(Copy, Clone)]
548pub struct DiagCtxtHandle<'a> {
549 dcx: &'a DiagCtxt,
550 tainted_with_errors: Option<&'a Cell<Option<ErrorGuaranteed>>>,
553}
554
555impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
556 type Target = &'a DiagCtxt;
557
558 fn deref(&self) -> &Self::Target {
559 &self.dcx
560 }
561}
562
563struct DiagCtxtInner {
567 flags: DiagCtxtFlags,
568
569 registry: Registry,
570
571 err_guars: Vec<ErrorGuaranteed>,
573 lint_err_guars: Vec<ErrorGuaranteed>,
576 delayed_bugs: Vec<(DelayedDiagInner, ErrorGuaranteed)>,
578
579 deduplicated_err_count: usize,
581 deduplicated_warn_count: usize,
583
584 emitter: Box<DynEmitter>,
585
586 must_produce_diag: Option<Backtrace>,
589
590 has_printed: bool,
593
594 suppressed_expected_diag: bool,
597
598 taught_diagnostics: FxHashSet<ErrCode>,
602
603 emitted_diagnostic_codes: FxIndexSet<ErrCode>,
605
606 emitted_diagnostics: FxHashSet<Hash128>,
610
611 stashed_diagnostics:
617 FxIndexMap<StashKey, FxIndexMap<Span, (DiagInner, Option<ErrorGuaranteed>)>>,
618
619 future_breakage_diagnostics: Vec<DiagInner>,
620
621 fulfilled_expectations: FxIndexSet<LintExpectationId>,
633
634 ice_file: Option<PathBuf>,
637}
638
639#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
641pub enum StashKey {
642 ItemNoType,
643 UnderscoreForArrayLengths,
644 EarlySyntaxWarning,
645 CallIntoMethod,
646 LifetimeIsChar,
649 MaybeFruTypo,
652 CallAssocMethod,
653 AssociatedTypeSuggestion,
654 Cycle,
656 UndeterminedMacroResolution,
657 ExprInPat,
659 GenericInFieldExpr,
663}
664
665fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
666 (*f)(diag)
667}
668
669pub static TRACK_DIAGNOSTIC: AtomicRef<
672 fn(DiagInner, &mut dyn FnMut(DiagInner) -> Option<ErrorGuaranteed>) -> Option<ErrorGuaranteed>,
673> = AtomicRef::new(&(default_track_diagnostic as _));
674
675#[derive(Copy, Clone, Default)]
676pub struct DiagCtxtFlags {
677 pub can_emit_warnings: bool,
680 pub treat_err_as_bug: Option<NonZero<usize>>,
683 pub eagerly_emit_delayed_bugs: bool,
686 pub macro_backtrace: bool,
689 pub deduplicate_diagnostics: bool,
691 pub track_diagnostics: bool,
693}
694
695impl Drop for DiagCtxtInner {
696 fn drop(&mut self) {
697 self.emit_stashed_diagnostics();
705
706 self.flush_delayed();
710
711 if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
715 if let Some(backtrace) = &self.must_produce_diag {
716 let suggestion = match backtrace.status() {
717 BacktraceStatus::Disabled => String::from(
718 "Backtraces are currently disabled: set `RUST_BACKTRACE=1` and re-run \
719 to see where it happened.",
720 ),
721 BacktraceStatus::Captured => format!(
722 "This happened in the following `must_produce_diag` call's backtrace:\n\
723 {backtrace}",
724 ),
725 _ => String::from("(impossible to capture backtrace where this happened)"),
726 };
727 panic!(
728 "`trimmed_def_paths` called, diagnostics were expected but none were emitted. \
729 Use `with_no_trimmed_paths` for debugging. {suggestion}"
730 );
731 }
732 }
733 }
734}
735
736impl DiagCtxt {
737 pub fn disable_warnings(mut self) -> Self {
738 self.inner.get_mut().flags.can_emit_warnings = false;
739 self
740 }
741
742 pub fn with_flags(mut self, flags: DiagCtxtFlags) -> Self {
743 self.inner.get_mut().flags = flags;
744 self
745 }
746
747 pub fn with_ice_file(mut self, ice_file: PathBuf) -> Self {
748 self.inner.get_mut().ice_file = Some(ice_file);
749 self
750 }
751
752 pub fn with_registry(mut self, registry: Registry) -> Self {
753 self.inner.get_mut().registry = registry;
754 self
755 }
756
757 pub fn new(emitter: Box<DynEmitter>) -> Self {
758 Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
759 }
760
761 pub fn make_silent(&self) {
762 let mut inner = self.inner.borrow_mut();
763 let translator = inner.emitter.translator().clone();
764 inner.emitter = Box::new(emitter::SilentEmitter { translator });
765 }
766
767 pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) {
768 self.inner.borrow_mut().emitter = emitter;
769 }
770
771 pub fn eagerly_translate<'a>(
773 &self,
774 message: DiagMessage,
775 args: impl Iterator<Item = DiagArg<'a>>,
776 ) -> SubdiagMessage {
777 let inner = self.inner.borrow();
778 inner.eagerly_translate(message, args)
779 }
780
781 pub fn eagerly_translate_to_string<'a>(
783 &self,
784 message: DiagMessage,
785 args: impl Iterator<Item = DiagArg<'a>>,
786 ) -> String {
787 let inner = self.inner.borrow();
788 inner.eagerly_translate_to_string(message, args)
789 }
790
791 pub fn can_emit_warnings(&self) -> bool {
795 self.inner.borrow_mut().flags.can_emit_warnings
796 }
797
798 pub fn reset_err_count(&self) {
804 let mut inner = self.inner.borrow_mut();
807 let DiagCtxtInner {
808 flags: _,
809 registry: _,
810 err_guars,
811 lint_err_guars,
812 delayed_bugs,
813 deduplicated_err_count,
814 deduplicated_warn_count,
815 emitter: _,
816 must_produce_diag,
817 has_printed,
818 suppressed_expected_diag,
819 taught_diagnostics,
820 emitted_diagnostic_codes,
821 emitted_diagnostics,
822 stashed_diagnostics,
823 future_breakage_diagnostics,
824 fulfilled_expectations,
825 ice_file: _,
826 } = inner.deref_mut();
827
828 *err_guars = Default::default();
831 *lint_err_guars = Default::default();
832 *delayed_bugs = Default::default();
833 *deduplicated_err_count = 0;
834 *deduplicated_warn_count = 0;
835 *must_produce_diag = None;
836 *has_printed = false;
837 *suppressed_expected_diag = false;
838 *taught_diagnostics = Default::default();
839 *emitted_diagnostic_codes = Default::default();
840 *emitted_diagnostics = Default::default();
841 *stashed_diagnostics = Default::default();
842 *future_breakage_diagnostics = Default::default();
843 *fulfilled_expectations = Default::default();
844 }
845
846 pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> {
847 DiagCtxtHandle { dcx: self, tainted_with_errors: None }
848 }
849
850 pub fn taintable_handle<'a>(
854 &'a self,
855 tainted_with_errors: &'a Cell<Option<ErrorGuaranteed>>,
856 ) -> DiagCtxtHandle<'a> {
857 DiagCtxtHandle { dcx: self, tainted_with_errors: Some(tainted_with_errors) }
858 }
859}
860
861impl<'a> DiagCtxtHandle<'a> {
862 pub fn stash_diagnostic(
884 &self,
885 span: Span,
886 key: StashKey,
887 diag: DiagInner,
888 ) -> Option<ErrorGuaranteed> {
889 let guar = match diag.level {
890 Bug | Fatal => {
891 self.span_bug(
892 span,
893 format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
894 );
895 }
896 Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
900 DelayedBug => {
901 return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors);
902 }
903 ForceWarning | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
904 | Expect => None,
905 };
906
907 self.inner
911 .borrow_mut()
912 .stashed_diagnostics
913 .entry(key)
914 .or_default()
915 .insert(span.with_parent(None), (diag, guar));
916
917 guar
918 }
919
920 pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
924 let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
926 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
927 )?;
928 assert!(!diag.is_error());
929 assert!(guar.is_none());
930 Some(Diag::new_diagnostic(self, diag))
931 }
932
933 pub fn try_steal_modify_and_emit_err<F>(
938 self,
939 span: Span,
940 key: StashKey,
941 mut modify_err: F,
942 ) -> Option<ErrorGuaranteed>
943 where
944 F: FnMut(&mut Diag<'_>),
945 {
946 let err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
948 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
949 );
950 err.map(|(err, guar)| {
951 assert_eq!(err.level, Error);
953 assert!(guar.is_some());
954 let mut err = Diag::<ErrorGuaranteed>::new_diagnostic(self, err);
955 modify_err(&mut err);
956 assert_eq!(err.level, Error);
957 err.emit()
958 })
959 }
960
961 pub fn try_steal_replace_and_emit_err(
965 self,
966 span: Span,
967 key: StashKey,
968 new_err: Diag<'_>,
969 ) -> ErrorGuaranteed {
970 let old_err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
972 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
973 );
974 match old_err {
975 Some((old_err, guar)) => {
976 assert_eq!(old_err.level, Error);
977 assert!(guar.is_some());
978 Diag::<ErrorGuaranteed>::new_diagnostic(self, old_err).cancel();
981 }
982 None => {}
983 };
984 new_err.emit()
985 }
986
987 pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
988 let inner = self.inner.borrow();
989 if let Some(stashed_diagnostics) = inner.stashed_diagnostics.get(&key)
990 && !stashed_diagnostics.is_empty()
991 {
992 stashed_diagnostics.contains_key(&span.with_parent(None))
993 } else {
994 false
995 }
996 }
997
998 pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
1000 self.inner.borrow_mut().emit_stashed_diagnostics()
1001 }
1002
1003 #[inline]
1005 pub fn err_count(&self) -> usize {
1006 let inner = self.inner.borrow();
1007 inner.err_guars.len()
1008 + inner.lint_err_guars.len()
1009 + inner
1010 .stashed_diagnostics
1011 .values()
1012 .map(|a| a.values().filter(|(_, guar)| guar.is_some()).count())
1013 .sum::<usize>()
1014 }
1015
1016 pub fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1019 self.inner.borrow().has_errors_excluding_lint_errors()
1020 }
1021
1022 pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
1024 self.inner.borrow().has_errors()
1025 }
1026
1027 pub fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1030 self.inner.borrow().has_errors_or_delayed_bugs()
1031 }
1032
1033 pub fn print_error_count(&self) {
1034 let mut inner = self.inner.borrow_mut();
1035
1036 assert!(inner.stashed_diagnostics.is_empty());
1039
1040 if inner.treat_err_as_bug() {
1041 return;
1042 }
1043
1044 let warnings = match inner.deduplicated_warn_count {
1045 0 => Cow::from(""),
1046 1 => Cow::from("1 warning emitted"),
1047 count => Cow::from(format!("{count} warnings emitted")),
1048 };
1049 let errors = match inner.deduplicated_err_count {
1050 0 => Cow::from(""),
1051 1 => Cow::from("aborting due to 1 previous error"),
1052 count => Cow::from(format!("aborting due to {count} previous errors")),
1053 };
1054
1055 match (errors.len(), warnings.len()) {
1056 (0, 0) => return,
1057 (0, _) => {
1058 inner.emit_diagnostic(
1061 DiagInner::new(ForceWarning, DiagMessage::Str(warnings)),
1062 None,
1063 );
1064 }
1065 (_, 0) => {
1066 inner.emit_diagnostic(DiagInner::new(Error, errors), self.tainted_with_errors);
1067 }
1068 (_, _) => {
1069 inner.emit_diagnostic(
1070 DiagInner::new(Error, format!("{errors}; {warnings}")),
1071 self.tainted_with_errors,
1072 );
1073 }
1074 }
1075
1076 let can_show_explain = inner.emitter.should_show_explain();
1077 let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty();
1078 if can_show_explain && are_there_diagnostics {
1079 let mut error_codes = inner
1080 .emitted_diagnostic_codes
1081 .iter()
1082 .filter_map(|&code| {
1083 if inner.registry.try_find_description(code).is_ok() {
1084 Some(code.to_string())
1085 } else {
1086 None
1087 }
1088 })
1089 .collect::<Vec<_>>();
1090 if !error_codes.is_empty() {
1091 error_codes.sort();
1092 if error_codes.len() > 1 {
1093 let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
1094 let msg1 = format!(
1095 "Some errors have detailed explanations: {}{}",
1096 error_codes[..limit].join(", "),
1097 if error_codes.len() > 9 { "..." } else { "." }
1098 );
1099 let msg2 = format!(
1100 "For more information about an error, try `rustc --explain {}`.",
1101 &error_codes[0]
1102 );
1103 inner.emit_diagnostic(DiagInner::new(FailureNote, msg1), None);
1104 inner.emit_diagnostic(DiagInner::new(FailureNote, msg2), None);
1105 } else {
1106 let msg = format!(
1107 "For more information about this error, try `rustc --explain {}`.",
1108 &error_codes[0]
1109 );
1110 inner.emit_diagnostic(DiagInner::new(FailureNote, msg), None);
1111 }
1112 }
1113 }
1114 }
1115
1116 pub fn abort_if_errors(&self) {
1121 if let Some(guar) = self.has_errors() {
1122 guar.raise_fatal();
1123 }
1124 }
1125
1126 pub fn must_teach(&self, code: ErrCode) -> bool {
1132 self.inner.borrow_mut().taught_diagnostics.insert(code)
1133 }
1134
1135 pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
1136 self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors)
1137 }
1138
1139 pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
1140 self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
1141 }
1142
1143 pub fn emit_timing_section_start(&self, record: TimingRecord) {
1144 self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::Start);
1145 }
1146
1147 pub fn emit_timing_section_end(&self, record: TimingRecord) {
1148 self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::End);
1149 }
1150
1151 pub fn emit_future_breakage_report(&self) {
1152 let inner = &mut *self.inner.borrow_mut();
1153 let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
1154 if !diags.is_empty() {
1155 inner.emitter.emit_future_breakage_report(diags, &inner.registry);
1156 }
1157 }
1158
1159 pub fn emit_unused_externs(
1160 &self,
1161 lint_level: rustc_lint_defs::Level,
1162 loud: bool,
1163 unused_externs: &[&str],
1164 ) {
1165 let mut inner = self.inner.borrow_mut();
1166
1167 if loud && lint_level.is_error() {
1178 #[allow(deprecated)]
1181 inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
1182 inner.panic_if_treat_err_as_bug();
1183 }
1184
1185 inner.emitter.emit_unused_externs(lint_level, unused_externs)
1186 }
1187
1188 #[must_use]
1191 pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
1192 std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
1193 }
1194
1195 pub fn flush_delayed(&self) {
1200 self.inner.borrow_mut().flush_delayed();
1201 }
1202
1203 #[track_caller]
1206 pub fn set_must_produce_diag(&self) {
1207 assert!(
1208 self.inner.borrow().must_produce_diag.is_none(),
1209 "should only need to collect a backtrace once"
1210 );
1211 self.inner.borrow_mut().must_produce_diag = Some(Backtrace::capture());
1212 }
1213}
1214
1215impl<'a> DiagCtxtHandle<'a> {
1220 #[track_caller]
1223 pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> {
1224 Diag::new(self, Bug, msg.into())
1225 }
1226
1227 #[track_caller]
1230 pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
1231 self.struct_bug(msg).emit()
1232 }
1233
1234 #[track_caller]
1237 pub fn struct_span_bug(
1238 self,
1239 span: impl Into<MultiSpan>,
1240 msg: impl Into<Cow<'static, str>>,
1241 ) -> Diag<'a, BugAbort> {
1242 self.struct_bug(msg).with_span(span)
1243 }
1244
1245 #[track_caller]
1248 pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
1249 self.struct_span_bug(span, msg.into()).emit()
1250 }
1251
1252 #[track_caller]
1253 pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> {
1254 bug.into_diag(self, Bug)
1255 }
1256
1257 #[track_caller]
1258 pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! {
1259 self.create_bug(bug).emit()
1260 }
1261
1262 #[rustc_lint_diagnostics]
1263 #[track_caller]
1264 pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> {
1265 Diag::new(self, Fatal, msg)
1266 }
1267
1268 #[rustc_lint_diagnostics]
1269 #[track_caller]
1270 pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
1271 self.struct_fatal(msg).emit()
1272 }
1273
1274 #[rustc_lint_diagnostics]
1275 #[track_caller]
1276 pub fn struct_span_fatal(
1277 self,
1278 span: impl Into<MultiSpan>,
1279 msg: impl Into<DiagMessage>,
1280 ) -> Diag<'a, FatalAbort> {
1281 self.struct_fatal(msg).with_span(span)
1282 }
1283
1284 #[rustc_lint_diagnostics]
1285 #[track_caller]
1286 pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
1287 self.struct_span_fatal(span, msg).emit()
1288 }
1289
1290 #[track_caller]
1291 pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> {
1292 fatal.into_diag(self, Fatal)
1293 }
1294
1295 #[track_caller]
1296 pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
1297 self.create_fatal(fatal).emit()
1298 }
1299
1300 #[track_caller]
1301 pub fn create_almost_fatal(
1302 self,
1303 fatal: impl Diagnostic<'a, FatalError>,
1304 ) -> Diag<'a, FatalError> {
1305 fatal.into_diag(self, Fatal)
1306 }
1307
1308 #[track_caller]
1309 pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError {
1310 self.create_almost_fatal(fatal).emit()
1311 }
1312
1313 #[rustc_lint_diagnostics]
1315 #[track_caller]
1316 pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> {
1317 Diag::new(self, Error, msg)
1318 }
1319
1320 #[rustc_lint_diagnostics]
1321 #[track_caller]
1322 pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
1323 self.struct_err(msg).emit()
1324 }
1325
1326 #[rustc_lint_diagnostics]
1327 #[track_caller]
1328 pub fn struct_span_err(
1329 self,
1330 span: impl Into<MultiSpan>,
1331 msg: impl Into<DiagMessage>,
1332 ) -> Diag<'a> {
1333 self.struct_err(msg).with_span(span)
1334 }
1335
1336 #[rustc_lint_diagnostics]
1337 #[track_caller]
1338 pub fn span_err(
1339 self,
1340 span: impl Into<MultiSpan>,
1341 msg: impl Into<DiagMessage>,
1342 ) -> ErrorGuaranteed {
1343 self.struct_span_err(span, msg).emit()
1344 }
1345
1346 #[track_caller]
1347 pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> {
1348 err.into_diag(self, Error)
1349 }
1350
1351 #[track_caller]
1352 pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
1353 self.create_err(err).emit()
1354 }
1355
1356 #[track_caller]
1361 pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
1362 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
1363 }
1364
1365 #[track_caller]
1373 pub fn span_delayed_bug(
1374 self,
1375 sp: impl Into<MultiSpan>,
1376 msg: impl Into<Cow<'static, str>>,
1377 ) -> ErrorGuaranteed {
1378 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
1379 }
1380
1381 #[rustc_lint_diagnostics]
1382 #[track_caller]
1383 pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1384 Diag::new(self, Warning, msg)
1385 }
1386
1387 #[rustc_lint_diagnostics]
1388 #[track_caller]
1389 pub fn warn(self, msg: impl Into<DiagMessage>) {
1390 self.struct_warn(msg).emit()
1391 }
1392
1393 #[rustc_lint_diagnostics]
1394 #[track_caller]
1395 pub fn struct_span_warn(
1396 self,
1397 span: impl Into<MultiSpan>,
1398 msg: impl Into<DiagMessage>,
1399 ) -> Diag<'a, ()> {
1400 self.struct_warn(msg).with_span(span)
1401 }
1402
1403 #[rustc_lint_diagnostics]
1404 #[track_caller]
1405 pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1406 self.struct_span_warn(span, msg).emit()
1407 }
1408
1409 #[track_caller]
1410 pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1411 warning.into_diag(self, Warning)
1412 }
1413
1414 #[track_caller]
1415 pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) {
1416 self.create_warn(warning).emit()
1417 }
1418
1419 #[rustc_lint_diagnostics]
1420 #[track_caller]
1421 pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1422 Diag::new(self, Note, msg)
1423 }
1424
1425 #[rustc_lint_diagnostics]
1426 #[track_caller]
1427 pub fn note(&self, msg: impl Into<DiagMessage>) {
1428 self.struct_note(msg).emit()
1429 }
1430
1431 #[rustc_lint_diagnostics]
1432 #[track_caller]
1433 pub fn struct_span_note(
1434 self,
1435 span: impl Into<MultiSpan>,
1436 msg: impl Into<DiagMessage>,
1437 ) -> Diag<'a, ()> {
1438 self.struct_note(msg).with_span(span)
1439 }
1440
1441 #[rustc_lint_diagnostics]
1442 #[track_caller]
1443 pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1444 self.struct_span_note(span, msg).emit()
1445 }
1446
1447 #[track_caller]
1448 pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1449 note.into_diag(self, Note)
1450 }
1451
1452 #[track_caller]
1453 pub fn emit_note(self, note: impl Diagnostic<'a, ()>) {
1454 self.create_note(note).emit()
1455 }
1456
1457 #[rustc_lint_diagnostics]
1458 #[track_caller]
1459 pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1460 Diag::new(self, Help, msg)
1461 }
1462
1463 #[rustc_lint_diagnostics]
1464 #[track_caller]
1465 pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1466 Diag::new(self, FailureNote, msg)
1467 }
1468
1469 #[rustc_lint_diagnostics]
1470 #[track_caller]
1471 pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1472 Diag::new(self, Allow, msg)
1473 }
1474
1475 #[rustc_lint_diagnostics]
1476 #[track_caller]
1477 pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> {
1478 Diag::new(self, Expect, msg).with_lint_id(id)
1479 }
1480}
1481
1482impl DiagCtxtInner {
1487 fn new(emitter: Box<DynEmitter>) -> Self {
1488 Self {
1489 flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
1490 registry: Registry::new(&[]),
1491 err_guars: Vec::new(),
1492 lint_err_guars: Vec::new(),
1493 delayed_bugs: Vec::new(),
1494 deduplicated_err_count: 0,
1495 deduplicated_warn_count: 0,
1496 emitter,
1497 must_produce_diag: None,
1498 has_printed: false,
1499 suppressed_expected_diag: false,
1500 taught_diagnostics: Default::default(),
1501 emitted_diagnostic_codes: Default::default(),
1502 emitted_diagnostics: Default::default(),
1503 stashed_diagnostics: Default::default(),
1504 future_breakage_diagnostics: Vec::new(),
1505 fulfilled_expectations: Default::default(),
1506 ice_file: None,
1507 }
1508 }
1509
1510 fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
1512 let mut guar = None;
1513 let has_errors = !self.err_guars.is_empty();
1514 for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
1515 for (_, (diag, _guar)) in stashed_diagnostics {
1516 if !diag.is_error() {
1517 if !diag.is_force_warn() && has_errors {
1521 continue;
1522 }
1523 }
1524 guar = guar.or(self.emit_diagnostic(diag, None));
1525 }
1526 }
1527 guar
1528 }
1529
1530 fn emit_diagnostic(
1532 &mut self,
1533 mut diagnostic: DiagInner,
1534 taint: Option<&Cell<Option<ErrorGuaranteed>>>,
1535 ) -> Option<ErrorGuaranteed> {
1536 if diagnostic.has_future_breakage() {
1537 assert_matches!(diagnostic.level, Error | ForceWarning | Warning | Allow | Expect);
1541 self.future_breakage_diagnostics.push(diagnostic.clone());
1542 }
1543
1544 match diagnostic.level {
1548 Bug => {}
1549 Fatal | Error => {
1550 if self.treat_next_err_as_bug() {
1551 diagnostic.level = Bug;
1553 }
1554 }
1555 DelayedBug => {
1556 if self.flags.eagerly_emit_delayed_bugs {
1561 if self.treat_next_err_as_bug() {
1563 diagnostic.level = Bug;
1564 } else {
1565 diagnostic.level = Error;
1566 }
1567 } else {
1568 return if let Some(guar) = self.has_errors() {
1571 Some(guar)
1572 } else {
1573 let backtrace = std::backtrace::Backtrace::capture();
1577 #[allow(deprecated)]
1581 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1582 self.delayed_bugs
1583 .push((DelayedDiagInner::with_backtrace(diagnostic, backtrace), guar));
1584 Some(guar)
1585 };
1586 }
1587 }
1588 ForceWarning if diagnostic.lint_id.is_none() => {} Warning => {
1590 if !self.flags.can_emit_warnings {
1591 if diagnostic.has_future_breakage() {
1593 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1595 }
1596 return None;
1597 }
1598 }
1599 Note | Help | FailureNote => {}
1600 OnceNote | OnceHelp => panic!("bad level: {:?}", diagnostic.level),
1601 Allow => {
1602 if diagnostic.has_future_breakage() {
1604 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1606 self.suppressed_expected_diag = true;
1607 }
1608 return None;
1609 }
1610 Expect | ForceWarning => {
1611 self.fulfilled_expectations.insert(diagnostic.lint_id.unwrap());
1612 if let Expect = diagnostic.level {
1613 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1615 self.suppressed_expected_diag = true;
1616 return None;
1617 }
1618 }
1619 }
1620
1621 TRACK_DIAGNOSTIC(diagnostic, &mut |mut diagnostic| {
1622 if let Some(code) = diagnostic.code {
1623 self.emitted_diagnostic_codes.insert(code);
1624 }
1625
1626 let already_emitted = {
1627 let mut hasher = StableHasher::new();
1628 diagnostic.hash(&mut hasher);
1629 let diagnostic_hash = hasher.finish();
1630 !self.emitted_diagnostics.insert(diagnostic_hash)
1631 };
1632
1633 let is_error = diagnostic.is_error();
1634 let is_lint = diagnostic.is_lint.is_some();
1635
1636 if !(self.flags.deduplicate_diagnostics && already_emitted) {
1639 debug!(?diagnostic);
1640 debug!(?self.emitted_diagnostics);
1641
1642 let not_yet_emitted = |sub: &mut Subdiag| {
1643 debug!(?sub);
1644 if sub.level != OnceNote && sub.level != OnceHelp {
1645 return true;
1646 }
1647 let mut hasher = StableHasher::new();
1648 sub.hash(&mut hasher);
1649 let diagnostic_hash = hasher.finish();
1650 debug!(?diagnostic_hash);
1651 self.emitted_diagnostics.insert(diagnostic_hash)
1652 };
1653 diagnostic.children.retain_mut(not_yet_emitted);
1654 if already_emitted {
1655 let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`";
1656 diagnostic.sub(Note, msg, MultiSpan::new());
1657 }
1658
1659 if is_error {
1660 self.deduplicated_err_count += 1;
1661 } else if matches!(diagnostic.level, ForceWarning | Warning) {
1662 self.deduplicated_warn_count += 1;
1663 }
1664 self.has_printed = true;
1665
1666 self.emitter.emit_diagnostic(diagnostic, &self.registry);
1667 }
1668
1669 if is_error {
1670 if !self.delayed_bugs.is_empty() {
1675 assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0);
1676 self.delayed_bugs.clear();
1677 self.delayed_bugs.shrink_to_fit();
1678 }
1679
1680 #[allow(deprecated)]
1683 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1684 if is_lint {
1685 self.lint_err_guars.push(guar);
1686 } else {
1687 if let Some(taint) = taint {
1688 taint.set(Some(guar));
1689 }
1690 self.err_guars.push(guar);
1691 }
1692 self.panic_if_treat_err_as_bug();
1693 Some(guar)
1694 } else {
1695 None
1696 }
1697 })
1698 }
1699
1700 fn treat_err_as_bug(&self) -> bool {
1701 self.flags
1702 .treat_err_as_bug
1703 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
1704 }
1705
1706 fn treat_next_err_as_bug(&self) -> bool {
1708 self.flags
1709 .treat_err_as_bug
1710 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
1711 }
1712
1713 fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1714 self.err_guars.get(0).copied().or_else(|| {
1715 if let Some((_diag, guar)) = self
1716 .stashed_diagnostics
1717 .values()
1718 .flat_map(|stashed_diagnostics| stashed_diagnostics.values())
1719 .find(|(diag, guar)| guar.is_some() && diag.is_lint.is_none())
1720 {
1721 *guar
1722 } else {
1723 None
1724 }
1725 })
1726 }
1727
1728 fn has_errors(&self) -> Option<ErrorGuaranteed> {
1729 self.err_guars.get(0).copied().or_else(|| self.lint_err_guars.get(0).copied()).or_else(
1730 || {
1731 self.stashed_diagnostics.values().find_map(|stashed_diagnostics| {
1732 stashed_diagnostics.values().find_map(|(_, guar)| *guar)
1733 })
1734 },
1735 )
1736 }
1737
1738 fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1739 self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
1740 }
1741
1742 fn eagerly_translate<'a>(
1744 &self,
1745 message: DiagMessage,
1746 args: impl Iterator<Item = DiagArg<'a>>,
1747 ) -> SubdiagMessage {
1748 SubdiagMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
1749 }
1750
1751 fn eagerly_translate_to_string<'a>(
1753 &self,
1754 message: DiagMessage,
1755 args: impl Iterator<Item = DiagArg<'a>>,
1756 ) -> String {
1757 let args = crate::translation::to_fluent_args(args);
1758 self.emitter
1759 .translator()
1760 .translate_message(&message, &args)
1761 .map_err(Report::new)
1762 .unwrap()
1763 .to_string()
1764 }
1765
1766 fn eagerly_translate_for_subdiag(
1767 &self,
1768 diag: &DiagInner,
1769 msg: impl Into<SubdiagMessage>,
1770 ) -> SubdiagMessage {
1771 let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
1772 self.eagerly_translate(msg, diag.args.iter())
1773 }
1774
1775 fn flush_delayed(&mut self) {
1776 assert!(self.stashed_diagnostics.is_empty());
1780
1781 if !self.err_guars.is_empty() {
1782 return;
1784 }
1785
1786 if self.delayed_bugs.is_empty() {
1787 return;
1789 }
1790
1791 let bugs: Vec<_> =
1792 std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
1793
1794 let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0"));
1795 let decorate = backtrace || self.ice_file.is_none();
1796 let mut out = self
1797 .ice_file
1798 .as_ref()
1799 .and_then(|file| std::fs::File::options().create(true).append(true).open(file).ok());
1800
1801 let note1 = "no errors encountered even though delayed bugs were created";
1806 let note2 = "those delayed bugs will now be shown as internal compiler errors";
1807 self.emit_diagnostic(DiagInner::new(Note, note1), None);
1808 self.emit_diagnostic(DiagInner::new(Note, note2), None);
1809
1810 for bug in bugs {
1811 if let Some(out) = &mut out {
1812 _ = write!(
1813 out,
1814 "delayed bug: {}\n{}\n",
1815 bug.inner
1816 .messages
1817 .iter()
1818 .filter_map(|(msg, _)| msg.as_str())
1819 .collect::<String>(),
1820 &bug.note
1821 );
1822 }
1823
1824 let mut bug = if decorate { bug.decorate(self) } else { bug.inner };
1825
1826 if bug.level != DelayedBug {
1828 bug.arg("level", bug.level);
1835 let msg = crate::fluent_generated::errors_invalid_flushed_delayed_diagnostic_level;
1836 let msg = self.eagerly_translate_for_subdiag(&bug, msg); bug.sub(Note, msg, bug.span.primary_span().unwrap().into());
1838 }
1839 bug.level = Bug;
1840
1841 self.emit_diagnostic(bug, None);
1842 }
1843
1844 panic::panic_any(DelayedBugPanic);
1846 }
1847
1848 fn panic_if_treat_err_as_bug(&self) {
1849 if self.treat_err_as_bug() {
1850 let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
1851 assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
1852 if n == 1 {
1853 panic!("aborting due to `-Z treat-err-as-bug=1`");
1854 } else {
1855 panic!("aborting after {n} errors due to `-Z treat-err-as-bug={n}`");
1856 }
1857 }
1858 }
1859}
1860
1861struct DelayedDiagInner {
1862 inner: DiagInner,
1863 note: Backtrace,
1864}
1865
1866impl DelayedDiagInner {
1867 fn with_backtrace(diagnostic: DiagInner, backtrace: Backtrace) -> Self {
1868 DelayedDiagInner { inner: diagnostic, note: backtrace }
1869 }
1870
1871 fn decorate(self, dcx: &DiagCtxtInner) -> DiagInner {
1872 let mut diag = self.inner;
1876 let msg = match self.note.status() {
1877 BacktraceStatus::Captured => crate::fluent_generated::errors_delayed_at_with_newline,
1878 _ => crate::fluent_generated::errors_delayed_at_without_newline,
1881 };
1882 diag.arg("emitted_at", diag.emitted_at.clone());
1883 diag.arg("note", self.note);
1884 let msg = dcx.eagerly_translate_for_subdiag(&diag, msg); diag.sub(Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into());
1886 diag
1887 }
1888}
1889
1890#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
1910pub enum Level {
1911 Bug,
1913
1914 Fatal,
1917
1918 Error,
1921
1922 DelayedBug,
1927
1928 ForceWarning,
1934
1935 Warning,
1938
1939 Note,
1941
1942 OnceNote,
1944
1945 Help,
1947
1948 OnceHelp,
1950
1951 FailureNote,
1954
1955 Allow,
1957
1958 Expect,
1960}
1961
1962impl fmt::Display for Level {
1963 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1964 self.to_str().fmt(f)
1965 }
1966}
1967
1968impl Level {
1969 fn color(self) -> anstyle::Style {
1970 match self {
1971 Bug | Fatal | Error | DelayedBug => AnsiColor::BrightRed.on_default(),
1972 ForceWarning | Warning => {
1973 if cfg!(windows) {
1974 AnsiColor::BrightYellow.on_default()
1975 } else {
1976 AnsiColor::Yellow.on_default()
1977 }
1978 }
1979 Note | OnceNote => AnsiColor::BrightGreen.on_default(),
1980 Help | OnceHelp => AnsiColor::BrightCyan.on_default(),
1981 FailureNote => anstyle::Style::new(),
1982 Allow | Expect => unreachable!(),
1983 }
1984 }
1985
1986 pub fn to_str(self) -> &'static str {
1987 match self {
1988 Bug | DelayedBug => "error: internal compiler error",
1989 Fatal | Error => "error",
1990 ForceWarning | Warning => "warning",
1991 Note | OnceNote => "note",
1992 Help | OnceHelp => "help",
1993 FailureNote => "failure-note",
1994 Allow | Expect => unreachable!(),
1995 }
1996 }
1997
1998 pub fn is_failure_note(&self) -> bool {
1999 matches!(*self, FailureNote)
2000 }
2001
2002 fn can_be_subdiag(&self) -> bool {
2004 match self {
2005 Bug | DelayedBug | Fatal | Error | ForceWarning | FailureNote | Allow | Expect => false,
2006
2007 Warning | Note | Help | OnceNote | OnceHelp => true,
2008 }
2009 }
2010}
2011
2012impl IntoDiagArg for Level {
2013 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
2014 DiagArgValue::Str(Cow::from(self.to_string()))
2015 }
2016}
2017
2018pub fn elided_lifetime_in_path_suggestion(
2020 source_map: &SourceMap,
2021 n: usize,
2022 path_span: Span,
2023 incl_angl_brckt: bool,
2024 insertion_span: Span,
2025) -> ElidedLifetimeInPathSubdiag {
2026 let expected = ExpectedLifetimeParameter { span: path_span, count: n };
2027 let indicate = source_map.is_span_accessible(insertion_span).then(|| {
2029 let anon_lts = vec!["'_"; n].join(", ");
2030 let suggestion =
2031 if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
2032
2033 IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
2034 });
2035
2036 ElidedLifetimeInPathSubdiag { expected, indicate }
2037}
2038
2039pub fn a_or_an(s: &str) -> &'static str {
2043 let mut chars = s.chars();
2044 let Some(mut first_alpha_char) = chars.next() else {
2045 return "a";
2046 };
2047 if first_alpha_char == '`' {
2048 let Some(next) = chars.next() else {
2049 return "a";
2050 };
2051 first_alpha_char = next;
2052 }
2053 if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
2054 "an"
2055 } else {
2056 "a"
2057 }
2058}
2059
2060#[derive(Clone, Copy, PartialEq, Hash, Debug)]
2061pub enum TerminalUrl {
2062 No,
2063 Yes,
2064 Auto,
2065}