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 assert_eq!(
386 substitution.parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
387 None,
388 "all spans must be disjoint",
389 );
390
391 substitution.parts.retain(|p| is_different(sm, &p.snippet, p.span));
395
396 let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
398 let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
399 let bounding_span = Span::with_root_ctxt(lo, hi);
400 let lines = sm.span_to_lines(bounding_span).ok()?;
402 assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
403
404 if !sm.ensure_source_file_source_present(&lines.file) {
406 return None;
407 }
408
409 let mut highlights = vec![];
410 let sf = &lines.file;
420 let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
421 prev_hi.col = CharPos::from_usize(0);
422 let mut prev_line =
423 lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
424 let mut buf = String::new();
425
426 let mut line_highlight = vec![];
427 let mut acc = 0;
430 let mut confusion_type = ConfusionType::None;
431 for part in &mut substitution.parts {
432 part.trim_trivial_replacements(sm);
436
437 let part_confusion = detect_confusion_type(sm, &part.snippet, part.span);
438 confusion_type = confusion_type.combine(part_confusion);
439 let cur_lo = sm.lookup_char_pos(part.span.lo());
440 if prev_hi.line == cur_lo.line {
441 let mut count =
442 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
443 while count > 0 {
444 highlights.push(std::mem::take(&mut line_highlight));
445 acc = 0;
446 count -= 1;
447 }
448 } else {
449 acc = 0;
450 highlights.push(std::mem::take(&mut line_highlight));
451 let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
452 while count > 0 {
453 highlights.push(std::mem::take(&mut line_highlight));
454 count -= 1;
455 }
456 for idx in prev_hi.line..(cur_lo.line - 1) {
458 if let Some(line) = sf.get_line(idx) {
459 buf.push_str(line.as_ref());
460 buf.push('\n');
461 highlights.push(std::mem::take(&mut line_highlight));
462 }
463 }
464 if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
465 let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
466 Some((i, _)) => i,
467 None => cur_line.len(),
468 };
469 buf.push_str(&cur_line[..end]);
470 }
471 }
472 let len: isize = part
474 .snippet
475 .split('\n')
476 .next()
477 .unwrap_or(&part.snippet)
478 .chars()
479 .map(|c| match c {
480 '\t' => 4,
481 _ => 1,
482 })
483 .sum();
484
485 line_highlight.push(SubstitutionHighlight {
486 start: (cur_lo.col.0 as isize + acc) as usize,
487 end: (cur_lo.col.0 as isize + acc + len) as usize,
488 });
489
490 buf.push_str(&part.snippet);
491 let cur_hi = sm.lookup_char_pos(part.span.hi());
492 acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
497 prev_hi = cur_hi;
498 prev_line = sf.get_line(prev_hi.line - 1);
499 for line in part.snippet.split('\n').skip(1) {
500 acc = 0;
501 highlights.push(std::mem::take(&mut line_highlight));
502 let end: usize = line
503 .chars()
504 .map(|c| match c {
505 '\t' => 4,
506 _ => 1,
507 })
508 .sum();
509 line_highlight.push(SubstitutionHighlight { start: 0, end });
510 }
511 }
512 highlights.push(std::mem::take(&mut line_highlight));
513 if !buf.ends_with('\n') {
515 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
516 }
517 while buf.ends_with('\n') {
519 buf.pop();
520 }
521 if highlights.iter().all(|parts| parts.is_empty()) {
522 None
523 } else {
524 Some((buf, substitution.parts, highlights, confusion_type))
525 }
526 })
527 .collect()
528 }
529}
530
531pub struct ExplicitBug;
534
535pub struct DelayedBugPanic;
538
539pub struct DiagCtxt {
543 inner: Lock<DiagCtxtInner>,
544}
545
546#[derive(Copy, Clone)]
547pub struct DiagCtxtHandle<'a> {
548 dcx: &'a DiagCtxt,
549 tainted_with_errors: Option<&'a Cell<Option<ErrorGuaranteed>>>,
552}
553
554impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
555 type Target = &'a DiagCtxt;
556
557 fn deref(&self) -> &Self::Target {
558 &self.dcx
559 }
560}
561
562struct DiagCtxtInner {
566 flags: DiagCtxtFlags,
567
568 registry: Registry,
569
570 err_guars: Vec<ErrorGuaranteed>,
572 lint_err_guars: Vec<ErrorGuaranteed>,
575 delayed_bugs: Vec<(DelayedDiagInner, ErrorGuaranteed)>,
577
578 deduplicated_err_count: usize,
580 deduplicated_warn_count: usize,
582
583 emitter: Box<DynEmitter>,
584
585 must_produce_diag: Option<Backtrace>,
588
589 has_printed: bool,
592
593 suppressed_expected_diag: bool,
596
597 taught_diagnostics: FxHashSet<ErrCode>,
601
602 emitted_diagnostic_codes: FxIndexSet<ErrCode>,
604
605 emitted_diagnostics: FxHashSet<Hash128>,
609
610 stashed_diagnostics:
616 FxIndexMap<StashKey, FxIndexMap<Span, (DiagInner, Option<ErrorGuaranteed>)>>,
617
618 future_breakage_diagnostics: Vec<DiagInner>,
619
620 fulfilled_expectations: FxIndexSet<LintExpectationId>,
632
633 ice_file: Option<PathBuf>,
636}
637
638#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
640pub enum StashKey {
641 ItemNoType,
642 UnderscoreForArrayLengths,
643 EarlySyntaxWarning,
644 CallIntoMethod,
645 LifetimeIsChar,
648 MaybeFruTypo,
651 CallAssocMethod,
652 AssociatedTypeSuggestion,
653 Cycle,
655 UndeterminedMacroResolution,
656 ExprInPat,
658 GenericInFieldExpr,
662}
663
664fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
665 (*f)(diag)
666}
667
668pub static TRACK_DIAGNOSTIC: AtomicRef<
671 fn(DiagInner, &mut dyn FnMut(DiagInner) -> Option<ErrorGuaranteed>) -> Option<ErrorGuaranteed>,
672> = AtomicRef::new(&(default_track_diagnostic as _));
673
674#[derive(Copy, Clone, Default)]
675pub struct DiagCtxtFlags {
676 pub can_emit_warnings: bool,
679 pub treat_err_as_bug: Option<NonZero<usize>>,
682 pub eagerly_emit_delayed_bugs: bool,
685 pub macro_backtrace: bool,
688 pub deduplicate_diagnostics: bool,
690 pub track_diagnostics: bool,
692}
693
694impl Drop for DiagCtxtInner {
695 fn drop(&mut self) {
696 self.emit_stashed_diagnostics();
704
705 self.flush_delayed();
709
710 if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
714 if let Some(backtrace) = &self.must_produce_diag {
715 let suggestion = match backtrace.status() {
716 BacktraceStatus::Disabled => String::from(
717 "Backtraces are currently disabled: set `RUST_BACKTRACE=1` and re-run \
718 to see where it happened.",
719 ),
720 BacktraceStatus::Captured => format!(
721 "This happened in the following `must_produce_diag` call's backtrace:\n\
722 {backtrace}",
723 ),
724 _ => String::from("(impossible to capture backtrace where this happened)"),
725 };
726 panic!(
727 "`trimmed_def_paths` called, diagnostics were expected but none were emitted. \
728 Use `with_no_trimmed_paths` for debugging. {suggestion}"
729 );
730 }
731 }
732 }
733}
734
735impl DiagCtxt {
736 pub fn disable_warnings(mut self) -> Self {
737 self.inner.get_mut().flags.can_emit_warnings = false;
738 self
739 }
740
741 pub fn with_flags(mut self, flags: DiagCtxtFlags) -> Self {
742 self.inner.get_mut().flags = flags;
743 self
744 }
745
746 pub fn with_ice_file(mut self, ice_file: PathBuf) -> Self {
747 self.inner.get_mut().ice_file = Some(ice_file);
748 self
749 }
750
751 pub fn with_registry(mut self, registry: Registry) -> Self {
752 self.inner.get_mut().registry = registry;
753 self
754 }
755
756 pub fn new(emitter: Box<DynEmitter>) -> Self {
757 Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
758 }
759
760 pub fn make_silent(&self) {
761 let mut inner = self.inner.borrow_mut();
762 let translator = inner.emitter.translator().clone();
763 inner.emitter = Box::new(emitter::SilentEmitter { translator });
764 }
765
766 pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) {
767 self.inner.borrow_mut().emitter = emitter;
768 }
769
770 pub fn eagerly_translate<'a>(
772 &self,
773 message: DiagMessage,
774 args: impl Iterator<Item = DiagArg<'a>>,
775 ) -> SubdiagMessage {
776 let inner = self.inner.borrow();
777 inner.eagerly_translate(message, args)
778 }
779
780 pub fn eagerly_translate_to_string<'a>(
782 &self,
783 message: DiagMessage,
784 args: impl Iterator<Item = DiagArg<'a>>,
785 ) -> String {
786 let inner = self.inner.borrow();
787 inner.eagerly_translate_to_string(message, args)
788 }
789
790 pub fn can_emit_warnings(&self) -> bool {
794 self.inner.borrow_mut().flags.can_emit_warnings
795 }
796
797 pub fn reset_err_count(&self) {
803 let mut inner = self.inner.borrow_mut();
806 let DiagCtxtInner {
807 flags: _,
808 registry: _,
809 err_guars,
810 lint_err_guars,
811 delayed_bugs,
812 deduplicated_err_count,
813 deduplicated_warn_count,
814 emitter: _,
815 must_produce_diag,
816 has_printed,
817 suppressed_expected_diag,
818 taught_diagnostics,
819 emitted_diagnostic_codes,
820 emitted_diagnostics,
821 stashed_diagnostics,
822 future_breakage_diagnostics,
823 fulfilled_expectations,
824 ice_file: _,
825 } = inner.deref_mut();
826
827 *err_guars = Default::default();
830 *lint_err_guars = Default::default();
831 *delayed_bugs = Default::default();
832 *deduplicated_err_count = 0;
833 *deduplicated_warn_count = 0;
834 *must_produce_diag = None;
835 *has_printed = false;
836 *suppressed_expected_diag = false;
837 *taught_diagnostics = Default::default();
838 *emitted_diagnostic_codes = Default::default();
839 *emitted_diagnostics = Default::default();
840 *stashed_diagnostics = Default::default();
841 *future_breakage_diagnostics = Default::default();
842 *fulfilled_expectations = Default::default();
843 }
844
845 pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> {
846 DiagCtxtHandle { dcx: self, tainted_with_errors: None }
847 }
848
849 pub fn taintable_handle<'a>(
853 &'a self,
854 tainted_with_errors: &'a Cell<Option<ErrorGuaranteed>>,
855 ) -> DiagCtxtHandle<'a> {
856 DiagCtxtHandle { dcx: self, tainted_with_errors: Some(tainted_with_errors) }
857 }
858}
859
860impl<'a> DiagCtxtHandle<'a> {
861 pub fn stash_diagnostic(
883 &self,
884 span: Span,
885 key: StashKey,
886 diag: DiagInner,
887 ) -> Option<ErrorGuaranteed> {
888 let guar = match diag.level {
889 Bug | Fatal => {
890 self.span_bug(
891 span,
892 format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
893 );
894 }
895 Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
899 DelayedBug => {
900 return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors);
901 }
902 ForceWarning | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
903 | Expect => None,
904 };
905
906 self.inner
910 .borrow_mut()
911 .stashed_diagnostics
912 .entry(key)
913 .or_default()
914 .insert(span.with_parent(None), (diag, guar));
915
916 guar
917 }
918
919 pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
923 let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
925 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
926 )?;
927 assert!(!diag.is_error());
928 assert!(guar.is_none());
929 Some(Diag::new_diagnostic(self, diag))
930 }
931
932 pub fn try_steal_modify_and_emit_err<F>(
937 self,
938 span: Span,
939 key: StashKey,
940 mut modify_err: F,
941 ) -> Option<ErrorGuaranteed>
942 where
943 F: FnMut(&mut Diag<'_>),
944 {
945 let err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
947 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
948 );
949 err.map(|(err, guar)| {
950 assert_eq!(err.level, Error);
952 assert!(guar.is_some());
953 let mut err = Diag::<ErrorGuaranteed>::new_diagnostic(self, err);
954 modify_err(&mut err);
955 assert_eq!(err.level, Error);
956 err.emit()
957 })
958 }
959
960 pub fn try_steal_replace_and_emit_err(
964 self,
965 span: Span,
966 key: StashKey,
967 new_err: Diag<'_>,
968 ) -> ErrorGuaranteed {
969 let old_err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
971 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
972 );
973 match old_err {
974 Some((old_err, guar)) => {
975 assert_eq!(old_err.level, Error);
976 assert!(guar.is_some());
977 Diag::<ErrorGuaranteed>::new_diagnostic(self, old_err).cancel();
980 }
981 None => {}
982 };
983 new_err.emit()
984 }
985
986 pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
987 let inner = self.inner.borrow();
988 if let Some(stashed_diagnostics) = inner.stashed_diagnostics.get(&key)
989 && !stashed_diagnostics.is_empty()
990 {
991 stashed_diagnostics.contains_key(&span.with_parent(None))
992 } else {
993 false
994 }
995 }
996
997 pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
999 self.inner.borrow_mut().emit_stashed_diagnostics()
1000 }
1001
1002 #[inline]
1004 pub fn err_count(&self) -> usize {
1005 let inner = self.inner.borrow();
1006 inner.err_guars.len()
1007 + inner.lint_err_guars.len()
1008 + inner
1009 .stashed_diagnostics
1010 .values()
1011 .map(|a| a.values().filter(|(_, guar)| guar.is_some()).count())
1012 .sum::<usize>()
1013 }
1014
1015 pub fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1018 self.inner.borrow().has_errors_excluding_lint_errors()
1019 }
1020
1021 pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
1023 self.inner.borrow().has_errors()
1024 }
1025
1026 pub fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1029 self.inner.borrow().has_errors_or_delayed_bugs()
1030 }
1031
1032 pub fn print_error_count(&self) {
1033 let mut inner = self.inner.borrow_mut();
1034
1035 assert!(inner.stashed_diagnostics.is_empty());
1038
1039 if inner.treat_err_as_bug() {
1040 return;
1041 }
1042
1043 let warnings = match inner.deduplicated_warn_count {
1044 0 => Cow::from(""),
1045 1 => Cow::from("1 warning emitted"),
1046 count => Cow::from(format!("{count} warnings emitted")),
1047 };
1048 let errors = match inner.deduplicated_err_count {
1049 0 => Cow::from(""),
1050 1 => Cow::from("aborting due to 1 previous error"),
1051 count => Cow::from(format!("aborting due to {count} previous errors")),
1052 };
1053
1054 match (errors.len(), warnings.len()) {
1055 (0, 0) => return,
1056 (0, _) => {
1057 inner.emit_diagnostic(
1060 DiagInner::new(ForceWarning, DiagMessage::Str(warnings)),
1061 None,
1062 );
1063 }
1064 (_, 0) => {
1065 inner.emit_diagnostic(DiagInner::new(Error, errors), self.tainted_with_errors);
1066 }
1067 (_, _) => {
1068 inner.emit_diagnostic(
1069 DiagInner::new(Error, format!("{errors}; {warnings}")),
1070 self.tainted_with_errors,
1071 );
1072 }
1073 }
1074
1075 let can_show_explain = inner.emitter.should_show_explain();
1076 let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty();
1077 if can_show_explain && are_there_diagnostics {
1078 let mut error_codes = inner
1079 .emitted_diagnostic_codes
1080 .iter()
1081 .filter_map(|&code| {
1082 if inner.registry.try_find_description(code).is_ok() {
1083 Some(code.to_string())
1084 } else {
1085 None
1086 }
1087 })
1088 .collect::<Vec<_>>();
1089 if !error_codes.is_empty() {
1090 error_codes.sort();
1091 if error_codes.len() > 1 {
1092 let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
1093 let msg1 = format!(
1094 "Some errors have detailed explanations: {}{}",
1095 error_codes[..limit].join(", "),
1096 if error_codes.len() > 9 { "..." } else { "." }
1097 );
1098 let msg2 = format!(
1099 "For more information about an error, try `rustc --explain {}`.",
1100 &error_codes[0]
1101 );
1102 inner.emit_diagnostic(DiagInner::new(FailureNote, msg1), None);
1103 inner.emit_diagnostic(DiagInner::new(FailureNote, msg2), None);
1104 } else {
1105 let msg = format!(
1106 "For more information about this error, try `rustc --explain {}`.",
1107 &error_codes[0]
1108 );
1109 inner.emit_diagnostic(DiagInner::new(FailureNote, msg), None);
1110 }
1111 }
1112 }
1113 }
1114
1115 pub fn abort_if_errors(&self) {
1120 if let Some(guar) = self.has_errors() {
1121 guar.raise_fatal();
1122 }
1123 }
1124
1125 pub fn must_teach(&self, code: ErrCode) -> bool {
1131 self.inner.borrow_mut().taught_diagnostics.insert(code)
1132 }
1133
1134 pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
1135 self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors)
1136 }
1137
1138 pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
1139 self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
1140 }
1141
1142 pub fn emit_timing_section_start(&self, record: TimingRecord) {
1143 self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::Start);
1144 }
1145
1146 pub fn emit_timing_section_end(&self, record: TimingRecord) {
1147 self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::End);
1148 }
1149
1150 pub fn emit_future_breakage_report(&self) {
1151 let inner = &mut *self.inner.borrow_mut();
1152 let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
1153 if !diags.is_empty() {
1154 inner.emitter.emit_future_breakage_report(diags, &inner.registry);
1155 }
1156 }
1157
1158 pub fn emit_unused_externs(
1159 &self,
1160 lint_level: rustc_lint_defs::Level,
1161 loud: bool,
1162 unused_externs: &[&str],
1163 ) {
1164 let mut inner = self.inner.borrow_mut();
1165
1166 if loud && lint_level.is_error() {
1177 #[allow(deprecated)]
1180 inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
1181 inner.panic_if_treat_err_as_bug();
1182 }
1183
1184 inner.emitter.emit_unused_externs(lint_level, unused_externs)
1185 }
1186
1187 #[must_use]
1190 pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
1191 std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
1192 }
1193
1194 pub fn flush_delayed(&self) {
1195 self.inner.borrow_mut().flush_delayed();
1196 }
1197
1198 #[track_caller]
1201 pub fn set_must_produce_diag(&self) {
1202 assert!(
1203 self.inner.borrow().must_produce_diag.is_none(),
1204 "should only need to collect a backtrace once"
1205 );
1206 self.inner.borrow_mut().must_produce_diag = Some(Backtrace::capture());
1207 }
1208}
1209
1210impl<'a> DiagCtxtHandle<'a> {
1215 #[track_caller]
1218 pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> {
1219 Diag::new(self, Bug, msg.into())
1220 }
1221
1222 #[track_caller]
1225 pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
1226 self.struct_bug(msg).emit()
1227 }
1228
1229 #[track_caller]
1232 pub fn struct_span_bug(
1233 self,
1234 span: impl Into<MultiSpan>,
1235 msg: impl Into<Cow<'static, str>>,
1236 ) -> Diag<'a, BugAbort> {
1237 self.struct_bug(msg).with_span(span)
1238 }
1239
1240 #[track_caller]
1243 pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
1244 self.struct_span_bug(span, msg.into()).emit()
1245 }
1246
1247 #[track_caller]
1248 pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> {
1249 bug.into_diag(self, Bug)
1250 }
1251
1252 #[track_caller]
1253 pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! {
1254 self.create_bug(bug).emit()
1255 }
1256
1257 #[rustc_lint_diagnostics]
1258 #[track_caller]
1259 pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> {
1260 Diag::new(self, Fatal, msg)
1261 }
1262
1263 #[rustc_lint_diagnostics]
1264 #[track_caller]
1265 pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
1266 self.struct_fatal(msg).emit()
1267 }
1268
1269 #[rustc_lint_diagnostics]
1270 #[track_caller]
1271 pub fn struct_span_fatal(
1272 self,
1273 span: impl Into<MultiSpan>,
1274 msg: impl Into<DiagMessage>,
1275 ) -> Diag<'a, FatalAbort> {
1276 self.struct_fatal(msg).with_span(span)
1277 }
1278
1279 #[rustc_lint_diagnostics]
1280 #[track_caller]
1281 pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
1282 self.struct_span_fatal(span, msg).emit()
1283 }
1284
1285 #[track_caller]
1286 pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> {
1287 fatal.into_diag(self, Fatal)
1288 }
1289
1290 #[track_caller]
1291 pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
1292 self.create_fatal(fatal).emit()
1293 }
1294
1295 #[track_caller]
1296 pub fn create_almost_fatal(
1297 self,
1298 fatal: impl Diagnostic<'a, FatalError>,
1299 ) -> Diag<'a, FatalError> {
1300 fatal.into_diag(self, Fatal)
1301 }
1302
1303 #[track_caller]
1304 pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError {
1305 self.create_almost_fatal(fatal).emit()
1306 }
1307
1308 #[rustc_lint_diagnostics]
1310 #[track_caller]
1311 pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> {
1312 Diag::new(self, Error, msg)
1313 }
1314
1315 #[rustc_lint_diagnostics]
1316 #[track_caller]
1317 pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
1318 self.struct_err(msg).emit()
1319 }
1320
1321 #[rustc_lint_diagnostics]
1322 #[track_caller]
1323 pub fn struct_span_err(
1324 self,
1325 span: impl Into<MultiSpan>,
1326 msg: impl Into<DiagMessage>,
1327 ) -> Diag<'a> {
1328 self.struct_err(msg).with_span(span)
1329 }
1330
1331 #[rustc_lint_diagnostics]
1332 #[track_caller]
1333 pub fn span_err(
1334 self,
1335 span: impl Into<MultiSpan>,
1336 msg: impl Into<DiagMessage>,
1337 ) -> ErrorGuaranteed {
1338 self.struct_span_err(span, msg).emit()
1339 }
1340
1341 #[track_caller]
1342 pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> {
1343 err.into_diag(self, Error)
1344 }
1345
1346 #[track_caller]
1347 pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
1348 self.create_err(err).emit()
1349 }
1350
1351 #[track_caller]
1356 pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
1357 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
1358 }
1359
1360 #[track_caller]
1368 pub fn span_delayed_bug(
1369 self,
1370 sp: impl Into<MultiSpan>,
1371 msg: impl Into<Cow<'static, str>>,
1372 ) -> ErrorGuaranteed {
1373 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
1374 }
1375
1376 #[rustc_lint_diagnostics]
1377 #[track_caller]
1378 pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1379 Diag::new(self, Warning, msg)
1380 }
1381
1382 #[rustc_lint_diagnostics]
1383 #[track_caller]
1384 pub fn warn(self, msg: impl Into<DiagMessage>) {
1385 self.struct_warn(msg).emit()
1386 }
1387
1388 #[rustc_lint_diagnostics]
1389 #[track_caller]
1390 pub fn struct_span_warn(
1391 self,
1392 span: impl Into<MultiSpan>,
1393 msg: impl Into<DiagMessage>,
1394 ) -> Diag<'a, ()> {
1395 self.struct_warn(msg).with_span(span)
1396 }
1397
1398 #[rustc_lint_diagnostics]
1399 #[track_caller]
1400 pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1401 self.struct_span_warn(span, msg).emit()
1402 }
1403
1404 #[track_caller]
1405 pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1406 warning.into_diag(self, Warning)
1407 }
1408
1409 #[track_caller]
1410 pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) {
1411 self.create_warn(warning).emit()
1412 }
1413
1414 #[rustc_lint_diagnostics]
1415 #[track_caller]
1416 pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1417 Diag::new(self, Note, msg)
1418 }
1419
1420 #[rustc_lint_diagnostics]
1421 #[track_caller]
1422 pub fn note(&self, msg: impl Into<DiagMessage>) {
1423 self.struct_note(msg).emit()
1424 }
1425
1426 #[rustc_lint_diagnostics]
1427 #[track_caller]
1428 pub fn struct_span_note(
1429 self,
1430 span: impl Into<MultiSpan>,
1431 msg: impl Into<DiagMessage>,
1432 ) -> Diag<'a, ()> {
1433 self.struct_note(msg).with_span(span)
1434 }
1435
1436 #[rustc_lint_diagnostics]
1437 #[track_caller]
1438 pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1439 self.struct_span_note(span, msg).emit()
1440 }
1441
1442 #[track_caller]
1443 pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1444 note.into_diag(self, Note)
1445 }
1446
1447 #[track_caller]
1448 pub fn emit_note(self, note: impl Diagnostic<'a, ()>) {
1449 self.create_note(note).emit()
1450 }
1451
1452 #[rustc_lint_diagnostics]
1453 #[track_caller]
1454 pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1455 Diag::new(self, Help, msg)
1456 }
1457
1458 #[rustc_lint_diagnostics]
1459 #[track_caller]
1460 pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1461 Diag::new(self, FailureNote, msg)
1462 }
1463
1464 #[rustc_lint_diagnostics]
1465 #[track_caller]
1466 pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1467 Diag::new(self, Allow, msg)
1468 }
1469
1470 #[rustc_lint_diagnostics]
1471 #[track_caller]
1472 pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> {
1473 Diag::new(self, Expect, msg).with_lint_id(id)
1474 }
1475}
1476
1477impl DiagCtxtInner {
1482 fn new(emitter: Box<DynEmitter>) -> Self {
1483 Self {
1484 flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
1485 registry: Registry::new(&[]),
1486 err_guars: Vec::new(),
1487 lint_err_guars: Vec::new(),
1488 delayed_bugs: Vec::new(),
1489 deduplicated_err_count: 0,
1490 deduplicated_warn_count: 0,
1491 emitter,
1492 must_produce_diag: None,
1493 has_printed: false,
1494 suppressed_expected_diag: false,
1495 taught_diagnostics: Default::default(),
1496 emitted_diagnostic_codes: Default::default(),
1497 emitted_diagnostics: Default::default(),
1498 stashed_diagnostics: Default::default(),
1499 future_breakage_diagnostics: Vec::new(),
1500 fulfilled_expectations: Default::default(),
1501 ice_file: None,
1502 }
1503 }
1504
1505 fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
1507 let mut guar = None;
1508 let has_errors = !self.err_guars.is_empty();
1509 for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
1510 for (_, (diag, _guar)) in stashed_diagnostics {
1511 if !diag.is_error() {
1512 if !diag.is_force_warn() && has_errors {
1516 continue;
1517 }
1518 }
1519 guar = guar.or(self.emit_diagnostic(diag, None));
1520 }
1521 }
1522 guar
1523 }
1524
1525 fn emit_diagnostic(
1527 &mut self,
1528 mut diagnostic: DiagInner,
1529 taint: Option<&Cell<Option<ErrorGuaranteed>>>,
1530 ) -> Option<ErrorGuaranteed> {
1531 if diagnostic.has_future_breakage() {
1532 assert_matches!(diagnostic.level, Error | ForceWarning | Warning | Allow | Expect);
1536 self.future_breakage_diagnostics.push(diagnostic.clone());
1537 }
1538
1539 match diagnostic.level {
1543 Bug => {}
1544 Fatal | Error => {
1545 if self.treat_next_err_as_bug() {
1546 diagnostic.level = Bug;
1548 }
1549 }
1550 DelayedBug => {
1551 if self.flags.eagerly_emit_delayed_bugs {
1556 if self.treat_next_err_as_bug() {
1558 diagnostic.level = Bug;
1559 } else {
1560 diagnostic.level = Error;
1561 }
1562 } else {
1563 return if let Some(guar) = self.has_errors() {
1566 Some(guar)
1567 } else {
1568 let backtrace = std::backtrace::Backtrace::capture();
1572 #[allow(deprecated)]
1576 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1577 self.delayed_bugs
1578 .push((DelayedDiagInner::with_backtrace(diagnostic, backtrace), guar));
1579 Some(guar)
1580 };
1581 }
1582 }
1583 ForceWarning if diagnostic.lint_id.is_none() => {} Warning => {
1585 if !self.flags.can_emit_warnings {
1586 if diagnostic.has_future_breakage() {
1588 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1590 }
1591 return None;
1592 }
1593 }
1594 Note | Help | FailureNote => {}
1595 OnceNote | OnceHelp => panic!("bad level: {:?}", diagnostic.level),
1596 Allow => {
1597 if diagnostic.has_future_breakage() {
1599 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1601 self.suppressed_expected_diag = true;
1602 }
1603 return None;
1604 }
1605 Expect | ForceWarning => {
1606 self.fulfilled_expectations.insert(diagnostic.lint_id.unwrap());
1607 if let Expect = diagnostic.level {
1608 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1610 self.suppressed_expected_diag = true;
1611 return None;
1612 }
1613 }
1614 }
1615
1616 TRACK_DIAGNOSTIC(diagnostic, &mut |mut diagnostic| {
1617 if let Some(code) = diagnostic.code {
1618 self.emitted_diagnostic_codes.insert(code);
1619 }
1620
1621 let already_emitted = {
1622 let mut hasher = StableHasher::new();
1623 diagnostic.hash(&mut hasher);
1624 let diagnostic_hash = hasher.finish();
1625 !self.emitted_diagnostics.insert(diagnostic_hash)
1626 };
1627
1628 let is_error = diagnostic.is_error();
1629 let is_lint = diagnostic.is_lint.is_some();
1630
1631 if !(self.flags.deduplicate_diagnostics && already_emitted) {
1634 debug!(?diagnostic);
1635 debug!(?self.emitted_diagnostics);
1636
1637 let not_yet_emitted = |sub: &mut Subdiag| {
1638 debug!(?sub);
1639 if sub.level != OnceNote && sub.level != OnceHelp {
1640 return true;
1641 }
1642 let mut hasher = StableHasher::new();
1643 sub.hash(&mut hasher);
1644 let diagnostic_hash = hasher.finish();
1645 debug!(?diagnostic_hash);
1646 self.emitted_diagnostics.insert(diagnostic_hash)
1647 };
1648 diagnostic.children.retain_mut(not_yet_emitted);
1649 if already_emitted {
1650 let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`";
1651 diagnostic.sub(Note, msg, MultiSpan::new());
1652 }
1653
1654 if is_error {
1655 self.deduplicated_err_count += 1;
1656 } else if matches!(diagnostic.level, ForceWarning | Warning) {
1657 self.deduplicated_warn_count += 1;
1658 }
1659 self.has_printed = true;
1660
1661 self.emitter.emit_diagnostic(diagnostic, &self.registry);
1662 }
1663
1664 if is_error {
1665 if !self.delayed_bugs.is_empty() {
1670 assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0);
1671 self.delayed_bugs.clear();
1672 self.delayed_bugs.shrink_to_fit();
1673 }
1674
1675 #[allow(deprecated)]
1678 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1679 if is_lint {
1680 self.lint_err_guars.push(guar);
1681 } else {
1682 if let Some(taint) = taint {
1683 taint.set(Some(guar));
1684 }
1685 self.err_guars.push(guar);
1686 }
1687 self.panic_if_treat_err_as_bug();
1688 Some(guar)
1689 } else {
1690 None
1691 }
1692 })
1693 }
1694
1695 fn treat_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() >= c.get())
1699 }
1700
1701 fn treat_next_err_as_bug(&self) -> bool {
1703 self.flags
1704 .treat_err_as_bug
1705 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
1706 }
1707
1708 fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1709 self.err_guars.get(0).copied().or_else(|| {
1710 if let Some((_diag, guar)) = self
1711 .stashed_diagnostics
1712 .values()
1713 .flat_map(|stashed_diagnostics| stashed_diagnostics.values())
1714 .find(|(diag, guar)| guar.is_some() && diag.is_lint.is_none())
1715 {
1716 *guar
1717 } else {
1718 None
1719 }
1720 })
1721 }
1722
1723 fn has_errors(&self) -> Option<ErrorGuaranteed> {
1724 self.err_guars.get(0).copied().or_else(|| self.lint_err_guars.get(0).copied()).or_else(
1725 || {
1726 self.stashed_diagnostics.values().find_map(|stashed_diagnostics| {
1727 stashed_diagnostics.values().find_map(|(_, guar)| *guar)
1728 })
1729 },
1730 )
1731 }
1732
1733 fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1734 self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
1735 }
1736
1737 fn eagerly_translate<'a>(
1739 &self,
1740 message: DiagMessage,
1741 args: impl Iterator<Item = DiagArg<'a>>,
1742 ) -> SubdiagMessage {
1743 SubdiagMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
1744 }
1745
1746 fn eagerly_translate_to_string<'a>(
1748 &self,
1749 message: DiagMessage,
1750 args: impl Iterator<Item = DiagArg<'a>>,
1751 ) -> String {
1752 let args = crate::translation::to_fluent_args(args);
1753 self.emitter
1754 .translator()
1755 .translate_message(&message, &args)
1756 .map_err(Report::new)
1757 .unwrap()
1758 .to_string()
1759 }
1760
1761 fn eagerly_translate_for_subdiag(
1762 &self,
1763 diag: &DiagInner,
1764 msg: impl Into<SubdiagMessage>,
1765 ) -> SubdiagMessage {
1766 let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
1767 self.eagerly_translate(msg, diag.args.iter())
1768 }
1769
1770 fn flush_delayed(&mut self) {
1771 assert!(self.stashed_diagnostics.is_empty());
1775
1776 if !self.err_guars.is_empty() {
1777 return;
1779 }
1780
1781 if self.delayed_bugs.is_empty() {
1782 return;
1784 }
1785
1786 let bugs: Vec<_> =
1787 std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
1788
1789 let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0"));
1790 let decorate = backtrace || self.ice_file.is_none();
1791 let mut out = self
1792 .ice_file
1793 .as_ref()
1794 .and_then(|file| std::fs::File::options().create(true).append(true).open(file).ok());
1795
1796 let note1 = "no errors encountered even though delayed bugs were created";
1801 let note2 = "those delayed bugs will now be shown as internal compiler errors";
1802 self.emit_diagnostic(DiagInner::new(Note, note1), None);
1803 self.emit_diagnostic(DiagInner::new(Note, note2), None);
1804
1805 for bug in bugs {
1806 if let Some(out) = &mut out {
1807 _ = write!(
1808 out,
1809 "delayed bug: {}\n{}\n",
1810 bug.inner
1811 .messages
1812 .iter()
1813 .filter_map(|(msg, _)| msg.as_str())
1814 .collect::<String>(),
1815 &bug.note
1816 );
1817 }
1818
1819 let mut bug = if decorate { bug.decorate(self) } else { bug.inner };
1820
1821 if bug.level != DelayedBug {
1823 bug.arg("level", bug.level);
1830 let msg = crate::fluent_generated::errors_invalid_flushed_delayed_diagnostic_level;
1831 let msg = self.eagerly_translate_for_subdiag(&bug, msg); bug.sub(Note, msg, bug.span.primary_span().unwrap().into());
1833 }
1834 bug.level = Bug;
1835
1836 self.emit_diagnostic(bug, None);
1837 }
1838
1839 panic::panic_any(DelayedBugPanic);
1841 }
1842
1843 fn panic_if_treat_err_as_bug(&self) {
1844 if self.treat_err_as_bug() {
1845 let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
1846 assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
1847 if n == 1 {
1848 panic!("aborting due to `-Z treat-err-as-bug=1`");
1849 } else {
1850 panic!("aborting after {n} errors due to `-Z treat-err-as-bug={n}`");
1851 }
1852 }
1853 }
1854}
1855
1856struct DelayedDiagInner {
1857 inner: DiagInner,
1858 note: Backtrace,
1859}
1860
1861impl DelayedDiagInner {
1862 fn with_backtrace(diagnostic: DiagInner, backtrace: Backtrace) -> Self {
1863 DelayedDiagInner { inner: diagnostic, note: backtrace }
1864 }
1865
1866 fn decorate(self, dcx: &DiagCtxtInner) -> DiagInner {
1867 let mut diag = self.inner;
1871 let msg = match self.note.status() {
1872 BacktraceStatus::Captured => crate::fluent_generated::errors_delayed_at_with_newline,
1873 _ => crate::fluent_generated::errors_delayed_at_without_newline,
1876 };
1877 diag.arg("emitted_at", diag.emitted_at.clone());
1878 diag.arg("note", self.note);
1879 let msg = dcx.eagerly_translate_for_subdiag(&diag, msg); diag.sub(Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into());
1881 diag
1882 }
1883}
1884
1885#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
1905pub enum Level {
1906 Bug,
1908
1909 Fatal,
1912
1913 Error,
1916
1917 DelayedBug,
1922
1923 ForceWarning,
1929
1930 Warning,
1933
1934 Note,
1936
1937 OnceNote,
1939
1940 Help,
1942
1943 OnceHelp,
1945
1946 FailureNote,
1949
1950 Allow,
1952
1953 Expect,
1955}
1956
1957impl fmt::Display for Level {
1958 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1959 self.to_str().fmt(f)
1960 }
1961}
1962
1963impl Level {
1964 fn color(self) -> ColorSpec {
1965 let mut spec = ColorSpec::new();
1966 match self {
1967 Bug | Fatal | Error | DelayedBug => {
1968 spec.set_fg(Some(Color::Red)).set_intense(true);
1969 }
1970 ForceWarning | Warning => {
1971 spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
1972 }
1973 Note | OnceNote => {
1974 spec.set_fg(Some(Color::Green)).set_intense(true);
1975 }
1976 Help | OnceHelp => {
1977 spec.set_fg(Some(Color::Cyan)).set_intense(true);
1978 }
1979 FailureNote => {}
1980 Allow | Expect => unreachable!(),
1981 }
1982 spec
1983 }
1984
1985 pub fn to_str(self) -> &'static str {
1986 match self {
1987 Bug | DelayedBug => "error: internal compiler error",
1988 Fatal | Error => "error",
1989 ForceWarning | Warning => "warning",
1990 Note | OnceNote => "note",
1991 Help | OnceHelp => "help",
1992 FailureNote => "failure-note",
1993 Allow | Expect => unreachable!(),
1994 }
1995 }
1996
1997 pub fn is_failure_note(&self) -> bool {
1998 matches!(*self, FailureNote)
1999 }
2000
2001 fn can_be_subdiag(&self) -> bool {
2003 match self {
2004 Bug | DelayedBug | Fatal | Error | ForceWarning | FailureNote | Allow | Expect => false,
2005
2006 Warning | Note | Help | OnceNote | OnceHelp => true,
2007 }
2008 }
2009}
2010
2011impl IntoDiagArg for Level {
2012 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
2013 DiagArgValue::Str(Cow::from(self.to_string()))
2014 }
2015}
2016
2017pub fn elided_lifetime_in_path_suggestion(
2019 source_map: &SourceMap,
2020 n: usize,
2021 path_span: Span,
2022 incl_angl_brckt: bool,
2023 insertion_span: Span,
2024) -> ElidedLifetimeInPathSubdiag {
2025 let expected = ExpectedLifetimeParameter { span: path_span, count: n };
2026 let indicate = source_map.is_span_accessible(insertion_span).then(|| {
2028 let anon_lts = vec!["'_"; n].join(", ");
2029 let suggestion =
2030 if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
2031
2032 IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
2033 });
2034
2035 ElidedLifetimeInPathSubdiag { expected, indicate }
2036}
2037
2038pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
2039 diag: &mut Diag<'a, G>,
2040 ambiguity: rustc_lint_defs::AmbiguityErrorDiag,
2041) {
2042 diag.span_label(ambiguity.label_span, ambiguity.label_msg);
2043 diag.note(ambiguity.note_msg);
2044 diag.span_note(ambiguity.b1_span, ambiguity.b1_note_msg);
2045 for help_msg in ambiguity.b1_help_msgs {
2046 diag.help(help_msg);
2047 }
2048 diag.span_note(ambiguity.b2_span, ambiguity.b2_note_msg);
2049 for help_msg in ambiguity.b2_help_msgs {
2050 diag.help(help_msg);
2051 }
2052}
2053
2054pub fn a_or_an(s: &str) -> &'static str {
2058 let mut chars = s.chars();
2059 let Some(mut first_alpha_char) = chars.next() else {
2060 return "a";
2061 };
2062 if first_alpha_char == '`' {
2063 let Some(next) = chars.next() else {
2064 return "a";
2065 };
2066 first_alpha_char = next;
2067 }
2068 if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
2069 "an"
2070 } else {
2071 "a"
2072 }
2073}
2074
2075#[derive(Clone, Copy, PartialEq, Hash, Debug)]
2076pub enum TerminalUrl {
2077 No,
2078 Yes,
2079 Auto,
2080}