1#![allow(incomplete_features)]
7#![allow(internal_features)]
8#![allow(rustc::diagnostic_outside_of_impl)]
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_into_inner)]
16#![feature(box_patterns)]
17#![feature(default_field_values)]
18#![feature(error_reporter)]
19#![feature(if_let_guard)]
20#![feature(let_chains)]
21#![feature(negative_impls)]
22#![feature(never_type)]
23#![feature(rustc_attrs)]
24#![feature(rustdoc_internals)]
25#![feature(trait_alias)]
26#![feature(try_blocks)]
27#![feature(yeet_expr)]
28extern crate self as rustc_errors;
31
32use std::assert_matches::assert_matches;
33use std::backtrace::{Backtrace, BacktraceStatus};
34use std::borrow::Cow;
35use std::cell::Cell;
36use std::error::Report;
37use std::ffi::OsStr;
38use std::hash::Hash;
39use std::io::Write;
40use std::num::NonZero;
41use std::ops::DerefMut;
42use std::path::{Path, PathBuf};
43use std::{fmt, panic};
44
45use Level::*;
46pub use codes::*;
47pub use diagnostic::{
48 BugAbort, Diag, DiagArg, DiagArgMap, DiagArgName, DiagArgValue, DiagInner, DiagStyledString,
49 Diagnostic, EmissionGuarantee, FatalAbort, IntoDiagArg, LintDiagnostic, StringPart, Subdiag,
50 SubdiagMessageOp, Subdiagnostic,
51};
52pub use diagnostic_impls::{
53 DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
54 IndicateAnonymousLifetime, SingleLabelManySpans,
55};
56pub use emitter::ColorConfig;
57use emitter::{DynEmitter, Emitter, is_case_difference, 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 DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel,
64 SubdiagMessage, fallback_fluent_bundle, fluent_bundle,
65};
66use rustc_hashes::Hash128;
67use rustc_lint_defs::LintExpectationId;
68pub use rustc_lint_defs::{Applicability, listify, pluralize};
69use rustc_macros::{Decodable, Encodable};
70pub use rustc_span::ErrorGuaranteed;
71pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
72use rustc_span::source_map::SourceMap;
73use rustc_span::{BytePos, DUMMY_SP, Loc, Span};
74pub use snippet::Style;
75pub use termcolor::{Color, ColorSpec, WriteColor};
78use tracing::debug;
79
80use crate::registry::Registry;
81
82pub mod annotate_snippet_emitter_writer;
83pub mod codes;
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 translation;
97
98pub type PResult<'a, T> = Result<T, Diag<'a>>;
99
100rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
101
102#[cfg(target_pointer_width = "64")]
104rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24);
105#[cfg(target_pointer_width = "64")]
106rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24);
107
108#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
109pub enum SuggestionStyle {
110 HideCodeInline,
112 HideCodeAlways,
114 CompletelyHidden,
116 ShowCode,
120 ShowAlways,
122}
123
124impl SuggestionStyle {
125 fn hide_inline(&self) -> bool {
126 !matches!(*self, SuggestionStyle::ShowCode)
127 }
128}
129
130#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
132pub enum Suggestions {
133 Enabled(Vec<CodeSuggestion>),
138 Sealed(Box<[CodeSuggestion]>),
142 Disabled,
146}
147
148impl Suggestions {
149 pub fn unwrap_tag(self) -> Vec<CodeSuggestion> {
151 match self {
152 Suggestions::Enabled(suggestions) => suggestions,
153 Suggestions::Sealed(suggestions) => suggestions.into_vec(),
154 Suggestions::Disabled => Vec::new(),
155 }
156 }
157}
158
159impl Default for Suggestions {
160 fn default() -> Self {
161 Self::Enabled(vec![])
162 }
163}
164
165#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
166pub struct CodeSuggestion {
167 pub substitutions: Vec<Substitution>,
189 pub msg: DiagMessage,
190 pub style: SuggestionStyle,
192 pub applicability: Applicability,
198}
199
200#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
201pub struct Substitution {
203 pub parts: Vec<SubstitutionPart>,
204}
205
206#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
207pub struct SubstitutionPart {
208 pub span: Span,
209 pub snippet: String,
210}
211
212#[derive(Debug, Clone, Copy)]
215pub(crate) struct SubstitutionHighlight {
216 start: usize,
217 end: usize,
218}
219
220impl SubstitutionPart {
221 pub fn is_addition(&self, sm: &SourceMap) -> bool {
222 !self.snippet.is_empty() && !self.replaces_meaningful_content(sm)
223 }
224
225 pub fn is_deletion(&self, sm: &SourceMap) -> bool {
226 self.snippet.trim().is_empty() && self.replaces_meaningful_content(sm)
227 }
228
229 pub fn is_replacement(&self, sm: &SourceMap) -> bool {
230 !self.snippet.is_empty() && self.replaces_meaningful_content(sm)
231 }
232
233 pub fn is_destructive_replacement(&self, sm: &SourceMap) -> bool {
238 self.is_replacement(sm)
239 && !sm
240 .span_to_snippet(self.span)
241 .is_ok_and(|snippet| as_substr(snippet.trim(), self.snippet.trim()).is_some())
242 }
243
244 fn replaces_meaningful_content(&self, sm: &SourceMap) -> bool {
245 sm.span_to_snippet(self.span)
246 .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty())
247 }
248
249 fn trim_trivial_replacements(&mut self, sm: &SourceMap) {
252 if self.snippet.is_empty() {
253 return;
254 }
255 let Ok(snippet) = sm.span_to_snippet(self.span) else {
256 return;
257 };
258
259 if let Some((prefix, substr, suffix)) = as_substr(&snippet, &self.snippet) {
260 self.span = Span::new(
261 self.span.lo() + BytePos(prefix as u32),
262 self.span.hi() - BytePos(suffix as u32),
263 self.span.ctxt(),
264 self.span.parent(),
265 );
266 self.snippet = substr.to_string();
267 }
268 }
269}
270
271fn as_substr<'a>(original: &'a str, suggestion: &'a str) -> Option<(usize, &'a str, usize)> {
276 let common_prefix = original
277 .chars()
278 .zip(suggestion.chars())
279 .take_while(|(c1, c2)| c1 == c2)
280 .map(|(c, _)| c.len_utf8())
281 .sum();
282 let original = &original[common_prefix..];
283 let suggestion = &suggestion[common_prefix..];
284 if suggestion.ends_with(original) {
285 let common_suffix = original.len();
286 Some((common_prefix, &suggestion[..suggestion.len() - original.len()], common_suffix))
287 } else {
288 None
289 }
290}
291
292impl CodeSuggestion {
293 pub(crate) fn splice_lines(
296 &self,
297 sm: &SourceMap,
298 ) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, bool)> {
299 use rustc_span::{CharPos, Pos};
304
305 fn push_trailing(
314 buf: &mut String,
315 line_opt: Option<&Cow<'_, str>>,
316 lo: &Loc,
317 hi_opt: Option<&Loc>,
318 ) -> usize {
319 let mut line_count = 0;
320 let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
323 if let Some(line) = line_opt {
324 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
325 let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
327 match hi_opt {
328 Some(hi) if hi > lo => {
330 line_count = line[lo..hi].matches('\n').count();
332 buf.push_str(&line[lo..hi])
333 }
334 Some(_) => (),
335 None => {
337 line_count = line[lo..].matches('\n').count();
339 buf.push_str(&line[lo..])
340 }
341 }
342 }
343 if hi_opt.is_none() {
345 buf.push('\n');
346 }
347 }
348 line_count
349 }
350
351 assert!(!self.substitutions.is_empty());
352
353 self.substitutions
354 .iter()
355 .filter(|subst| {
356 let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
359 if invalid {
360 debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
361 }
362 !invalid
363 })
364 .cloned()
365 .filter_map(|mut substitution| {
366 substitution.parts.sort_by_key(|part| part.span.lo());
369
370 let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
372 let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
373 let bounding_span = Span::with_root_ctxt(lo, hi);
374 let lines = sm.span_to_lines(bounding_span).ok()?;
376 assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
377
378 if !sm.ensure_source_file_source_present(&lines.file) {
380 return None;
381 }
382
383 let mut highlights = vec![];
384 let sf = &lines.file;
394 let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
395 prev_hi.col = CharPos::from_usize(0);
396 let mut prev_line =
397 lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
398 let mut buf = String::new();
399
400 let mut line_highlight = vec![];
401 let mut acc = 0;
404 let mut only_capitalization = false;
405 for part in &mut substitution.parts {
406 part.trim_trivial_replacements(sm);
410
411 only_capitalization |= is_case_difference(sm, &part.snippet, part.span);
412 let cur_lo = sm.lookup_char_pos(part.span.lo());
413 if prev_hi.line == cur_lo.line {
414 let mut count =
415 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
416 while count > 0 {
417 highlights.push(std::mem::take(&mut line_highlight));
418 acc = 0;
419 count -= 1;
420 }
421 } else {
422 acc = 0;
423 highlights.push(std::mem::take(&mut line_highlight));
424 let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
425 while count > 0 {
426 highlights.push(std::mem::take(&mut line_highlight));
427 count -= 1;
428 }
429 for idx in prev_hi.line..(cur_lo.line - 1) {
431 if let Some(line) = sf.get_line(idx) {
432 buf.push_str(line.as_ref());
433 buf.push('\n');
434 highlights.push(std::mem::take(&mut line_highlight));
435 }
436 }
437 if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
438 let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
439 Some((i, _)) => i,
440 None => cur_line.len(),
441 };
442 buf.push_str(&cur_line[..end]);
443 }
444 }
445 let len: isize = part
447 .snippet
448 .split('\n')
449 .next()
450 .unwrap_or(&part.snippet)
451 .chars()
452 .map(|c| match c {
453 '\t' => 4,
454 _ => 1,
455 })
456 .sum();
457 if !is_different(sm, &part.snippet, part.span) {
458 } else {
462 line_highlight.push(SubstitutionHighlight {
463 start: (cur_lo.col.0 as isize + acc) as usize,
464 end: (cur_lo.col.0 as isize + acc + len) as usize,
465 });
466 }
467 buf.push_str(&part.snippet);
468 let cur_hi = sm.lookup_char_pos(part.span.hi());
469 acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
474 prev_hi = cur_hi;
475 prev_line = sf.get_line(prev_hi.line - 1);
476 for line in part.snippet.split('\n').skip(1) {
477 acc = 0;
478 highlights.push(std::mem::take(&mut line_highlight));
479 let end: usize = line
480 .chars()
481 .map(|c| match c {
482 '\t' => 4,
483 _ => 1,
484 })
485 .sum();
486 line_highlight.push(SubstitutionHighlight { start: 0, end });
487 }
488 }
489 highlights.push(std::mem::take(&mut line_highlight));
490 if !buf.ends_with('\n') {
492 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
493 }
494 while buf.ends_with('\n') {
496 buf.pop();
497 }
498 if highlights.iter().all(|parts| parts.is_empty()) {
499 None
500 } else {
501 Some((buf, substitution.parts, highlights, only_capitalization))
502 }
503 })
504 .collect()
505 }
506}
507
508pub struct ExplicitBug;
511
512pub struct DelayedBugPanic;
515
516pub struct DiagCtxt {
520 inner: Lock<DiagCtxtInner>,
521}
522
523#[derive(Copy, Clone)]
524pub struct DiagCtxtHandle<'a> {
525 dcx: &'a DiagCtxt,
526 tainted_with_errors: Option<&'a Cell<Option<ErrorGuaranteed>>>,
529}
530
531impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
532 type Target = &'a DiagCtxt;
533
534 fn deref(&self) -> &Self::Target {
535 &self.dcx
536 }
537}
538
539struct DiagCtxtInner {
543 flags: DiagCtxtFlags,
544
545 registry: Registry,
546
547 err_guars: Vec<ErrorGuaranteed>,
549 lint_err_guars: Vec<ErrorGuaranteed>,
552 delayed_bugs: Vec<(DelayedDiagInner, ErrorGuaranteed)>,
554
555 deduplicated_err_count: usize,
557 deduplicated_warn_count: usize,
559
560 emitter: Box<DynEmitter>,
561
562 must_produce_diag: Option<Backtrace>,
565
566 has_printed: bool,
569
570 suppressed_expected_diag: bool,
573
574 taught_diagnostics: FxHashSet<ErrCode>,
578
579 emitted_diagnostic_codes: FxIndexSet<ErrCode>,
581
582 emitted_diagnostics: FxHashSet<Hash128>,
586
587 stashed_diagnostics: FxIndexMap<(Span, StashKey), (DiagInner, Option<ErrorGuaranteed>)>,
593
594 future_breakage_diagnostics: Vec<DiagInner>,
595
596 fulfilled_expectations: FxIndexSet<LintExpectationId>,
608
609 ice_file: Option<PathBuf>,
612}
613
614#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
616pub enum StashKey {
617 ItemNoType,
618 UnderscoreForArrayLengths,
619 EarlySyntaxWarning,
620 CallIntoMethod,
621 LifetimeIsChar,
624 MaybeFruTypo,
627 CallAssocMethod,
628 AssociatedTypeSuggestion,
629 Cycle,
631 UndeterminedMacroResolution,
632 ExprInPat,
634 GenericInFieldExpr,
638}
639
640fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
641 (*f)(diag)
642}
643
644pub static TRACK_DIAGNOSTIC: AtomicRef<
647 fn(DiagInner, &mut dyn FnMut(DiagInner) -> Option<ErrorGuaranteed>) -> Option<ErrorGuaranteed>,
648> = AtomicRef::new(&(default_track_diagnostic as _));
649
650#[derive(Copy, Clone, Default)]
651pub struct DiagCtxtFlags {
652 pub can_emit_warnings: bool,
655 pub treat_err_as_bug: Option<NonZero<usize>>,
658 pub eagerly_emit_delayed_bugs: bool,
661 pub macro_backtrace: bool,
664 pub deduplicate_diagnostics: bool,
666 pub track_diagnostics: bool,
668}
669
670impl Drop for DiagCtxtInner {
671 fn drop(&mut self) {
672 self.emit_stashed_diagnostics();
680
681 self.flush_delayed();
685
686 if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
690 if let Some(backtrace) = &self.must_produce_diag {
691 let suggestion = match backtrace.status() {
692 BacktraceStatus::Disabled => String::from(
693 "Backtraces are currently disabled: set `RUST_BACKTRACE=1` and re-run \
694 to see where it happened.",
695 ),
696 BacktraceStatus::Captured => format!(
697 "This happened in the following `must_produce_diag` call's backtrace:\n\
698 {backtrace}",
699 ),
700 _ => String::from("(impossible to capture backtrace where this happened)"),
701 };
702 panic!(
703 "`trimmed_def_paths` called, diagnostics were expected but none were emitted. \
704 Use `with_no_trimmed_paths` for debugging. {suggestion}"
705 );
706 }
707 }
708 }
709}
710
711impl DiagCtxt {
712 pub fn disable_warnings(mut self) -> Self {
713 self.inner.get_mut().flags.can_emit_warnings = false;
714 self
715 }
716
717 pub fn with_flags(mut self, flags: DiagCtxtFlags) -> Self {
718 self.inner.get_mut().flags = flags;
719 self
720 }
721
722 pub fn with_ice_file(mut self, ice_file: PathBuf) -> Self {
723 self.inner.get_mut().ice_file = Some(ice_file);
724 self
725 }
726
727 pub fn with_registry(mut self, registry: Registry) -> Self {
728 self.inner.get_mut().registry = registry;
729 self
730 }
731
732 pub fn new(emitter: Box<DynEmitter>) -> Self {
733 Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
734 }
735
736 pub fn make_silent(&self, fatal_note: Option<String>, emit_fatal_diagnostic: bool) {
737 struct FalseEmitter;
740
741 impl Emitter for FalseEmitter {
742 fn emit_diagnostic(&mut self, _: DiagInner, _: &Registry) {
743 unimplemented!("false emitter must only used during `make_silent`")
744 }
745
746 fn source_map(&self) -> Option<&SourceMap> {
747 unimplemented!("false emitter must only used during `make_silent`")
748 }
749 }
750
751 impl translation::Translate for FalseEmitter {
752 fn fluent_bundle(&self) -> Option<&FluentBundle> {
753 unimplemented!("false emitter must only used during `make_silent`")
754 }
755
756 fn fallback_fluent_bundle(&self) -> &FluentBundle {
757 unimplemented!("false emitter must only used during `make_silent`")
758 }
759 }
760
761 let mut inner = self.inner.borrow_mut();
762 let mut prev_emitter = Box::new(FalseEmitter) as Box<dyn Emitter + DynSend>;
763 std::mem::swap(&mut inner.emitter, &mut prev_emitter);
764 let new_emitter = Box::new(emitter::SilentEmitter {
765 fatal_emitter: prev_emitter,
766 fatal_note,
767 emit_fatal_diagnostic,
768 });
769 inner.emitter = new_emitter;
770 }
771
772 pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) {
773 self.inner.borrow_mut().emitter = emitter;
774 }
775
776 pub fn eagerly_translate<'a>(
778 &self,
779 message: DiagMessage,
780 args: impl Iterator<Item = DiagArg<'a>>,
781 ) -> SubdiagMessage {
782 let inner = self.inner.borrow();
783 inner.eagerly_translate(message, args)
784 }
785
786 pub fn eagerly_translate_to_string<'a>(
788 &self,
789 message: DiagMessage,
790 args: impl Iterator<Item = DiagArg<'a>>,
791 ) -> String {
792 let inner = self.inner.borrow();
793 inner.eagerly_translate_to_string(message, args)
794 }
795
796 pub fn can_emit_warnings(&self) -> bool {
800 self.inner.borrow_mut().flags.can_emit_warnings
801 }
802
803 pub fn reset_err_count(&self) {
809 let mut inner = self.inner.borrow_mut();
812 let DiagCtxtInner {
813 flags: _,
814 registry: _,
815 err_guars,
816 lint_err_guars,
817 delayed_bugs,
818 deduplicated_err_count,
819 deduplicated_warn_count,
820 emitter: _,
821 must_produce_diag,
822 has_printed,
823 suppressed_expected_diag,
824 taught_diagnostics,
825 emitted_diagnostic_codes,
826 emitted_diagnostics,
827 stashed_diagnostics,
828 future_breakage_diagnostics,
829 fulfilled_expectations,
830 ice_file: _,
831 } = inner.deref_mut();
832
833 *err_guars = Default::default();
836 *lint_err_guars = Default::default();
837 *delayed_bugs = Default::default();
838 *deduplicated_err_count = 0;
839 *deduplicated_warn_count = 0;
840 *must_produce_diag = None;
841 *has_printed = false;
842 *suppressed_expected_diag = false;
843 *taught_diagnostics = Default::default();
844 *emitted_diagnostic_codes = Default::default();
845 *emitted_diagnostics = Default::default();
846 *stashed_diagnostics = Default::default();
847 *future_breakage_diagnostics = Default::default();
848 *fulfilled_expectations = Default::default();
849 }
850
851 pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> {
852 DiagCtxtHandle { dcx: self, tainted_with_errors: None }
853 }
854
855 pub fn taintable_handle<'a>(
859 &'a self,
860 tainted_with_errors: &'a Cell<Option<ErrorGuaranteed>>,
861 ) -> DiagCtxtHandle<'a> {
862 DiagCtxtHandle { dcx: self, tainted_with_errors: Some(tainted_with_errors) }
863 }
864}
865
866impl<'a> DiagCtxtHandle<'a> {
867 pub fn stash_diagnostic(
889 &self,
890 span: Span,
891 key: StashKey,
892 diag: DiagInner,
893 ) -> Option<ErrorGuaranteed> {
894 let guar = match diag.level {
895 Bug | Fatal => {
896 self.span_bug(
897 span,
898 format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
899 );
900 }
901 Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
905 DelayedBug => {
906 return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors);
907 }
908 ForceWarning(_) | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
909 | Expect(_) => None,
910 };
911
912 let key = (span.with_parent(None), key);
916 self.inner.borrow_mut().stashed_diagnostics.insert(key, (diag, guar));
917
918 guar
919 }
920
921 pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
925 let key = (span.with_parent(None), key);
926 let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.swap_remove(&key)?;
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 key = (span.with_parent(None), key);
947 let err = self.inner.borrow_mut().stashed_diagnostics.swap_remove(&key);
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 key = (span.with_parent(None), key);
970 let old_err = self.inner.borrow_mut().stashed_diagnostics.swap_remove(&key);
972 match old_err {
973 Some((old_err, guar)) => {
974 assert_eq!(old_err.level, Error);
975 assert!(guar.is_some());
976 Diag::<ErrorGuaranteed>::new_diagnostic(self, old_err).cancel();
979 }
980 None => {}
981 };
982 new_err.emit()
983 }
984
985 pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
986 self.inner.borrow().stashed_diagnostics.get(&(span.with_parent(None), key)).is_some()
987 }
988
989 pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
991 self.inner.borrow_mut().emit_stashed_diagnostics()
992 }
993
994 #[inline]
996 pub fn err_count(&self) -> usize {
997 let inner = self.inner.borrow();
998 inner.err_guars.len()
999 + inner.lint_err_guars.len()
1000 + inner.stashed_diagnostics.values().filter(|(_diag, guar)| guar.is_some()).count()
1001 }
1002
1003 pub fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1006 self.inner.borrow().has_errors_excluding_lint_errors()
1007 }
1008
1009 pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
1011 self.inner.borrow().has_errors()
1012 }
1013
1014 pub fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1017 self.inner.borrow().has_errors_or_delayed_bugs()
1018 }
1019
1020 pub fn print_error_count(&self) {
1021 let mut inner = self.inner.borrow_mut();
1022
1023 assert!(inner.stashed_diagnostics.is_empty());
1026
1027 if inner.treat_err_as_bug() {
1028 return;
1029 }
1030
1031 let warnings = match inner.deduplicated_warn_count {
1032 0 => Cow::from(""),
1033 1 => Cow::from("1 warning emitted"),
1034 count => Cow::from(format!("{count} warnings emitted")),
1035 };
1036 let errors = match inner.deduplicated_err_count {
1037 0 => Cow::from(""),
1038 1 => Cow::from("aborting due to 1 previous error"),
1039 count => Cow::from(format!("aborting due to {count} previous errors")),
1040 };
1041
1042 match (errors.len(), warnings.len()) {
1043 (0, 0) => return,
1044 (0, _) => {
1045 inner.emit_diagnostic(
1048 DiagInner::new(ForceWarning(None), DiagMessage::Str(warnings)),
1049 None,
1050 );
1051 }
1052 (_, 0) => {
1053 inner.emit_diagnostic(DiagInner::new(Error, errors), self.tainted_with_errors);
1054 }
1055 (_, _) => {
1056 inner.emit_diagnostic(
1057 DiagInner::new(Error, format!("{errors}; {warnings}")),
1058 self.tainted_with_errors,
1059 );
1060 }
1061 }
1062
1063 let can_show_explain = inner.emitter.should_show_explain();
1064 let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty();
1065 if can_show_explain && are_there_diagnostics {
1066 let mut error_codes = inner
1067 .emitted_diagnostic_codes
1068 .iter()
1069 .filter_map(|&code| {
1070 if inner.registry.try_find_description(code).is_ok() {
1071 Some(code.to_string())
1072 } else {
1073 None
1074 }
1075 })
1076 .collect::<Vec<_>>();
1077 if !error_codes.is_empty() {
1078 error_codes.sort();
1079 if error_codes.len() > 1 {
1080 let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
1081 let msg1 = format!(
1082 "Some errors have detailed explanations: {}{}",
1083 error_codes[..limit].join(", "),
1084 if error_codes.len() > 9 { "..." } else { "." }
1085 );
1086 let msg2 = format!(
1087 "For more information about an error, try `rustc --explain {}`.",
1088 &error_codes[0]
1089 );
1090 inner.emit_diagnostic(DiagInner::new(FailureNote, msg1), None);
1091 inner.emit_diagnostic(DiagInner::new(FailureNote, msg2), None);
1092 } else {
1093 let msg = format!(
1094 "For more information about this error, try `rustc --explain {}`.",
1095 &error_codes[0]
1096 );
1097 inner.emit_diagnostic(DiagInner::new(FailureNote, msg), None);
1098 }
1099 }
1100 }
1101 }
1102
1103 pub fn abort_if_errors(&self) {
1108 if let Some(guar) = self.has_errors() {
1109 guar.raise_fatal();
1110 }
1111 }
1112
1113 pub fn must_teach(&self, code: ErrCode) -> bool {
1119 self.inner.borrow_mut().taught_diagnostics.insert(code)
1120 }
1121
1122 pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
1123 self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors)
1124 }
1125
1126 pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
1127 self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
1128 }
1129
1130 pub fn emit_future_breakage_report(&self) {
1131 let inner = &mut *self.inner.borrow_mut();
1132 let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
1133 if !diags.is_empty() {
1134 inner.emitter.emit_future_breakage_report(diags, &inner.registry);
1135 }
1136 }
1137
1138 pub fn emit_unused_externs(
1139 &self,
1140 lint_level: rustc_lint_defs::Level,
1141 loud: bool,
1142 unused_externs: &[&str],
1143 ) {
1144 let mut inner = self.inner.borrow_mut();
1145
1146 if loud && lint_level.is_error() {
1157 #[allow(deprecated)]
1160 inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
1161 inner.panic_if_treat_err_as_bug();
1162 }
1163
1164 inner.emitter.emit_unused_externs(lint_level, unused_externs)
1165 }
1166
1167 #[must_use]
1170 pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
1171 std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
1172 }
1173
1174 pub fn flush_delayed(&self) {
1175 self.inner.borrow_mut().flush_delayed();
1176 }
1177
1178 #[track_caller]
1181 pub fn set_must_produce_diag(&self) {
1182 assert!(
1183 self.inner.borrow().must_produce_diag.is_none(),
1184 "should only need to collect a backtrace once"
1185 );
1186 self.inner.borrow_mut().must_produce_diag = Some(Backtrace::capture());
1187 }
1188}
1189
1190impl<'a> DiagCtxtHandle<'a> {
1195 #[track_caller]
1198 pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> {
1199 Diag::new(self, Bug, msg.into())
1200 }
1201
1202 #[track_caller]
1205 pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
1206 self.struct_bug(msg).emit()
1207 }
1208
1209 #[track_caller]
1212 pub fn struct_span_bug(
1213 self,
1214 span: impl Into<MultiSpan>,
1215 msg: impl Into<Cow<'static, str>>,
1216 ) -> Diag<'a, BugAbort> {
1217 self.struct_bug(msg).with_span(span)
1218 }
1219
1220 #[track_caller]
1223 pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
1224 self.struct_span_bug(span, msg.into()).emit()
1225 }
1226
1227 #[track_caller]
1228 pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> {
1229 bug.into_diag(self, Bug)
1230 }
1231
1232 #[track_caller]
1233 pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! {
1234 self.create_bug(bug).emit()
1235 }
1236
1237 #[rustc_lint_diagnostics]
1238 #[track_caller]
1239 pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> {
1240 Diag::new(self, Fatal, msg)
1241 }
1242
1243 #[rustc_lint_diagnostics]
1244 #[track_caller]
1245 pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
1246 self.struct_fatal(msg).emit()
1247 }
1248
1249 #[rustc_lint_diagnostics]
1250 #[track_caller]
1251 pub fn struct_span_fatal(
1252 self,
1253 span: impl Into<MultiSpan>,
1254 msg: impl Into<DiagMessage>,
1255 ) -> Diag<'a, FatalAbort> {
1256 self.struct_fatal(msg).with_span(span)
1257 }
1258
1259 #[rustc_lint_diagnostics]
1260 #[track_caller]
1261 pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
1262 self.struct_span_fatal(span, msg).emit()
1263 }
1264
1265 #[track_caller]
1266 pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> {
1267 fatal.into_diag(self, Fatal)
1268 }
1269
1270 #[track_caller]
1271 pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
1272 self.create_fatal(fatal).emit()
1273 }
1274
1275 #[track_caller]
1276 pub fn create_almost_fatal(
1277 self,
1278 fatal: impl Diagnostic<'a, FatalError>,
1279 ) -> Diag<'a, FatalError> {
1280 fatal.into_diag(self, Fatal)
1281 }
1282
1283 #[track_caller]
1284 pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError {
1285 self.create_almost_fatal(fatal).emit()
1286 }
1287
1288 #[rustc_lint_diagnostics]
1290 #[track_caller]
1291 pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> {
1292 Diag::new(self, Error, msg)
1293 }
1294
1295 #[rustc_lint_diagnostics]
1296 #[track_caller]
1297 pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
1298 self.struct_err(msg).emit()
1299 }
1300
1301 #[rustc_lint_diagnostics]
1302 #[track_caller]
1303 pub fn struct_span_err(
1304 self,
1305 span: impl Into<MultiSpan>,
1306 msg: impl Into<DiagMessage>,
1307 ) -> Diag<'a> {
1308 self.struct_err(msg).with_span(span)
1309 }
1310
1311 #[rustc_lint_diagnostics]
1312 #[track_caller]
1313 pub fn span_err(
1314 self,
1315 span: impl Into<MultiSpan>,
1316 msg: impl Into<DiagMessage>,
1317 ) -> ErrorGuaranteed {
1318 self.struct_span_err(span, msg).emit()
1319 }
1320
1321 #[track_caller]
1322 pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> {
1323 err.into_diag(self, Error)
1324 }
1325
1326 #[track_caller]
1327 pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
1328 self.create_err(err).emit()
1329 }
1330
1331 #[track_caller]
1336 pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
1337 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
1338 }
1339
1340 #[track_caller]
1348 pub fn span_delayed_bug(
1349 self,
1350 sp: impl Into<MultiSpan>,
1351 msg: impl Into<Cow<'static, str>>,
1352 ) -> ErrorGuaranteed {
1353 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
1354 }
1355
1356 #[rustc_lint_diagnostics]
1357 #[track_caller]
1358 pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1359 Diag::new(self, Warning, msg)
1360 }
1361
1362 #[rustc_lint_diagnostics]
1363 #[track_caller]
1364 pub fn warn(self, msg: impl Into<DiagMessage>) {
1365 self.struct_warn(msg).emit()
1366 }
1367
1368 #[rustc_lint_diagnostics]
1369 #[track_caller]
1370 pub fn struct_span_warn(
1371 self,
1372 span: impl Into<MultiSpan>,
1373 msg: impl Into<DiagMessage>,
1374 ) -> Diag<'a, ()> {
1375 self.struct_warn(msg).with_span(span)
1376 }
1377
1378 #[rustc_lint_diagnostics]
1379 #[track_caller]
1380 pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1381 self.struct_span_warn(span, msg).emit()
1382 }
1383
1384 #[track_caller]
1385 pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1386 warning.into_diag(self, Warning)
1387 }
1388
1389 #[track_caller]
1390 pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) {
1391 self.create_warn(warning).emit()
1392 }
1393
1394 #[rustc_lint_diagnostics]
1395 #[track_caller]
1396 pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1397 Diag::new(self, Note, msg)
1398 }
1399
1400 #[rustc_lint_diagnostics]
1401 #[track_caller]
1402 pub fn note(&self, msg: impl Into<DiagMessage>) {
1403 self.struct_note(msg).emit()
1404 }
1405
1406 #[rustc_lint_diagnostics]
1407 #[track_caller]
1408 pub fn struct_span_note(
1409 self,
1410 span: impl Into<MultiSpan>,
1411 msg: impl Into<DiagMessage>,
1412 ) -> Diag<'a, ()> {
1413 self.struct_note(msg).with_span(span)
1414 }
1415
1416 #[rustc_lint_diagnostics]
1417 #[track_caller]
1418 pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1419 self.struct_span_note(span, msg).emit()
1420 }
1421
1422 #[track_caller]
1423 pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1424 note.into_diag(self, Note)
1425 }
1426
1427 #[track_caller]
1428 pub fn emit_note(self, note: impl Diagnostic<'a, ()>) {
1429 self.create_note(note).emit()
1430 }
1431
1432 #[rustc_lint_diagnostics]
1433 #[track_caller]
1434 pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1435 Diag::new(self, Help, msg)
1436 }
1437
1438 #[rustc_lint_diagnostics]
1439 #[track_caller]
1440 pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1441 Diag::new(self, FailureNote, msg)
1442 }
1443
1444 #[rustc_lint_diagnostics]
1445 #[track_caller]
1446 pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1447 Diag::new(self, Allow, msg)
1448 }
1449
1450 #[rustc_lint_diagnostics]
1451 #[track_caller]
1452 pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> {
1453 Diag::new(self, Expect(id), msg)
1454 }
1455}
1456
1457impl DiagCtxtInner {
1462 fn new(emitter: Box<DynEmitter>) -> Self {
1463 Self {
1464 flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
1465 registry: Registry::new(&[]),
1466 err_guars: Vec::new(),
1467 lint_err_guars: Vec::new(),
1468 delayed_bugs: Vec::new(),
1469 deduplicated_err_count: 0,
1470 deduplicated_warn_count: 0,
1471 emitter,
1472 must_produce_diag: None,
1473 has_printed: false,
1474 suppressed_expected_diag: false,
1475 taught_diagnostics: Default::default(),
1476 emitted_diagnostic_codes: Default::default(),
1477 emitted_diagnostics: Default::default(),
1478 stashed_diagnostics: Default::default(),
1479 future_breakage_diagnostics: Vec::new(),
1480 fulfilled_expectations: Default::default(),
1481 ice_file: None,
1482 }
1483 }
1484
1485 fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
1487 let mut guar = None;
1488 let has_errors = !self.err_guars.is_empty();
1489 for (_, (diag, _guar)) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
1490 if !diag.is_error() {
1491 if !diag.is_force_warn() && has_errors {
1495 continue;
1496 }
1497 }
1498 guar = guar.or(self.emit_diagnostic(diag, None));
1499 }
1500 guar
1501 }
1502
1503 fn emit_diagnostic(
1505 &mut self,
1506 mut diagnostic: DiagInner,
1507 taint: Option<&Cell<Option<ErrorGuaranteed>>>,
1508 ) -> Option<ErrorGuaranteed> {
1509 if diagnostic.has_future_breakage() {
1510 assert_matches!(diagnostic.level, Error | Warning | Allow | Expect(_));
1514 self.future_breakage_diagnostics.push(diagnostic.clone());
1515 }
1516
1517 match diagnostic.level {
1521 Bug => {}
1522 Fatal | Error => {
1523 if self.treat_next_err_as_bug() {
1524 diagnostic.level = Bug;
1526 }
1527 }
1528 DelayedBug => {
1529 if self.flags.eagerly_emit_delayed_bugs {
1534 if self.treat_next_err_as_bug() {
1536 diagnostic.level = Bug;
1537 } else {
1538 diagnostic.level = Error;
1539 }
1540 } else {
1541 return if let Some(guar) = self.has_errors() {
1544 Some(guar)
1545 } else {
1546 let backtrace = std::backtrace::Backtrace::capture();
1550 #[allow(deprecated)]
1554 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1555 self.delayed_bugs
1556 .push((DelayedDiagInner::with_backtrace(diagnostic, backtrace), guar));
1557 Some(guar)
1558 };
1559 }
1560 }
1561 ForceWarning(None) => {} Warning => {
1563 if !self.flags.can_emit_warnings {
1564 if diagnostic.has_future_breakage() {
1566 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1568 }
1569 return None;
1570 }
1571 }
1572 Note | Help | FailureNote => {}
1573 OnceNote | OnceHelp => panic!("bad level: {:?}", diagnostic.level),
1574 Allow => {
1575 if diagnostic.has_future_breakage() {
1577 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1579 self.suppressed_expected_diag = true;
1580 }
1581 return None;
1582 }
1583 Expect(expect_id) | ForceWarning(Some(expect_id)) => {
1584 self.fulfilled_expectations.insert(expect_id);
1585 if let Expect(_) = diagnostic.level {
1586 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1588 self.suppressed_expected_diag = true;
1589 return None;
1590 }
1591 }
1592 }
1593
1594 TRACK_DIAGNOSTIC(diagnostic, &mut |mut diagnostic| {
1595 if let Some(code) = diagnostic.code {
1596 self.emitted_diagnostic_codes.insert(code);
1597 }
1598
1599 let already_emitted = {
1600 let mut hasher = StableHasher::new();
1601 diagnostic.hash(&mut hasher);
1602 let diagnostic_hash = hasher.finish();
1603 !self.emitted_diagnostics.insert(diagnostic_hash)
1604 };
1605
1606 let is_error = diagnostic.is_error();
1607 let is_lint = diagnostic.is_lint.is_some();
1608
1609 if !(self.flags.deduplicate_diagnostics && already_emitted) {
1612 debug!(?diagnostic);
1613 debug!(?self.emitted_diagnostics);
1614
1615 let not_yet_emitted = |sub: &mut Subdiag| {
1616 debug!(?sub);
1617 if sub.level != OnceNote && sub.level != OnceHelp {
1618 return true;
1619 }
1620 let mut hasher = StableHasher::new();
1621 sub.hash(&mut hasher);
1622 let diagnostic_hash = hasher.finish();
1623 debug!(?diagnostic_hash);
1624 self.emitted_diagnostics.insert(diagnostic_hash)
1625 };
1626 diagnostic.children.retain_mut(not_yet_emitted);
1627 if already_emitted {
1628 let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`";
1629 diagnostic.sub(Note, msg, MultiSpan::new());
1630 }
1631
1632 if is_error {
1633 self.deduplicated_err_count += 1;
1634 } else if matches!(diagnostic.level, ForceWarning(_) | Warning) {
1635 self.deduplicated_warn_count += 1;
1636 }
1637 self.has_printed = true;
1638
1639 self.emitter.emit_diagnostic(diagnostic, &self.registry);
1640 }
1641
1642 if is_error {
1643 if !self.delayed_bugs.is_empty() {
1648 assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0);
1649 self.delayed_bugs.clear();
1650 self.delayed_bugs.shrink_to_fit();
1651 }
1652
1653 #[allow(deprecated)]
1656 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1657 if is_lint {
1658 self.lint_err_guars.push(guar);
1659 } else {
1660 if let Some(taint) = taint {
1661 taint.set(Some(guar));
1662 }
1663 self.err_guars.push(guar);
1664 }
1665 self.panic_if_treat_err_as_bug();
1666 Some(guar)
1667 } else {
1668 None
1669 }
1670 })
1671 }
1672
1673 fn treat_err_as_bug(&self) -> bool {
1674 self.flags
1675 .treat_err_as_bug
1676 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
1677 }
1678
1679 fn treat_next_err_as_bug(&self) -> bool {
1681 self.flags
1682 .treat_err_as_bug
1683 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
1684 }
1685
1686 fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1687 self.err_guars.get(0).copied().or_else(|| {
1688 if let Some((_diag, guar)) = self
1689 .stashed_diagnostics
1690 .values()
1691 .find(|(diag, guar)| guar.is_some() && diag.is_lint.is_none())
1692 {
1693 *guar
1694 } else {
1695 None
1696 }
1697 })
1698 }
1699
1700 fn has_errors(&self) -> Option<ErrorGuaranteed> {
1701 self.err_guars.get(0).copied().or_else(|| self.lint_err_guars.get(0).copied()).or_else(
1702 || {
1703 if let Some((_diag, guar)) =
1704 self.stashed_diagnostics.values().find(|(_diag, guar)| guar.is_some())
1705 {
1706 *guar
1707 } else {
1708 None
1709 }
1710 },
1711 )
1712 }
1713
1714 fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1715 self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
1716 }
1717
1718 fn eagerly_translate<'a>(
1720 &self,
1721 message: DiagMessage,
1722 args: impl Iterator<Item = DiagArg<'a>>,
1723 ) -> SubdiagMessage {
1724 SubdiagMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
1725 }
1726
1727 fn eagerly_translate_to_string<'a>(
1729 &self,
1730 message: DiagMessage,
1731 args: impl Iterator<Item = DiagArg<'a>>,
1732 ) -> String {
1733 let args = crate::translation::to_fluent_args(args);
1734 self.emitter.translate_message(&message, &args).map_err(Report::new).unwrap().to_string()
1735 }
1736
1737 fn eagerly_translate_for_subdiag(
1738 &self,
1739 diag: &DiagInner,
1740 msg: impl Into<SubdiagMessage>,
1741 ) -> SubdiagMessage {
1742 let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
1743 self.eagerly_translate(msg, diag.args.iter())
1744 }
1745
1746 fn flush_delayed(&mut self) {
1747 assert!(self.stashed_diagnostics.is_empty());
1751
1752 if !self.err_guars.is_empty() {
1753 return;
1755 }
1756
1757 if self.delayed_bugs.is_empty() {
1758 return;
1760 }
1761
1762 let bugs: Vec<_> =
1763 std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
1764
1765 let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0"));
1766 let decorate = backtrace || self.ice_file.is_none();
1767 let mut out = self
1768 .ice_file
1769 .as_ref()
1770 .and_then(|file| std::fs::File::options().create(true).append(true).open(file).ok());
1771
1772 let note1 = "no errors encountered even though delayed bugs were created";
1777 let note2 = "those delayed bugs will now be shown as internal compiler errors";
1778 self.emit_diagnostic(DiagInner::new(Note, note1), None);
1779 self.emit_diagnostic(DiagInner::new(Note, note2), None);
1780
1781 for bug in bugs {
1782 if let Some(out) = &mut out {
1783 _ = write!(
1784 out,
1785 "delayed bug: {}\n{}\n",
1786 bug.inner
1787 .messages
1788 .iter()
1789 .filter_map(|(msg, _)| msg.as_str())
1790 .collect::<String>(),
1791 &bug.note
1792 );
1793 }
1794
1795 let mut bug = if decorate { bug.decorate(self) } else { bug.inner };
1796
1797 if bug.level != DelayedBug {
1799 bug.arg("level", bug.level);
1806 let msg = crate::fluent_generated::errors_invalid_flushed_delayed_diagnostic_level;
1807 let msg = self.eagerly_translate_for_subdiag(&bug, msg); bug.sub(Note, msg, bug.span.primary_span().unwrap().into());
1809 }
1810 bug.level = Bug;
1811
1812 self.emit_diagnostic(bug, None);
1813 }
1814
1815 panic::panic_any(DelayedBugPanic);
1817 }
1818
1819 fn panic_if_treat_err_as_bug(&self) {
1820 if self.treat_err_as_bug() {
1821 let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
1822 assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
1823 if n == 1 {
1824 panic!("aborting due to `-Z treat-err-as-bug=1`");
1825 } else {
1826 panic!("aborting after {n} errors due to `-Z treat-err-as-bug={n}`");
1827 }
1828 }
1829 }
1830}
1831
1832struct DelayedDiagInner {
1833 inner: DiagInner,
1834 note: Backtrace,
1835}
1836
1837impl DelayedDiagInner {
1838 fn with_backtrace(diagnostic: DiagInner, backtrace: Backtrace) -> Self {
1839 DelayedDiagInner { inner: diagnostic, note: backtrace }
1840 }
1841
1842 fn decorate(self, dcx: &DiagCtxtInner) -> DiagInner {
1843 let mut diag = self.inner;
1847 let msg = match self.note.status() {
1848 BacktraceStatus::Captured => crate::fluent_generated::errors_delayed_at_with_newline,
1849 _ => crate::fluent_generated::errors_delayed_at_without_newline,
1852 };
1853 diag.arg("emitted_at", diag.emitted_at.clone());
1854 diag.arg("note", self.note);
1855 let msg = dcx.eagerly_translate_for_subdiag(&diag, msg); diag.sub(Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into());
1857 diag
1858 }
1859}
1860
1861#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
1881pub enum Level {
1882 Bug,
1884
1885 Fatal,
1888
1889 Error,
1892
1893 DelayedBug,
1898
1899 ForceWarning(Option<LintExpectationId>),
1905
1906 Warning,
1909
1910 Note,
1912
1913 OnceNote,
1915
1916 Help,
1918
1919 OnceHelp,
1921
1922 FailureNote,
1925
1926 Allow,
1928
1929 Expect(LintExpectationId),
1931}
1932
1933impl fmt::Display for Level {
1934 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1935 self.to_str().fmt(f)
1936 }
1937}
1938
1939impl Level {
1940 fn color(self) -> ColorSpec {
1941 let mut spec = ColorSpec::new();
1942 match self {
1943 Bug | Fatal | Error | DelayedBug => {
1944 spec.set_fg(Some(Color::Red)).set_intense(true);
1945 }
1946 ForceWarning(_) | Warning => {
1947 spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
1948 }
1949 Note | OnceNote => {
1950 spec.set_fg(Some(Color::Green)).set_intense(true);
1951 }
1952 Help | OnceHelp => {
1953 spec.set_fg(Some(Color::Cyan)).set_intense(true);
1954 }
1955 FailureNote => {}
1956 Allow | Expect(_) => unreachable!(),
1957 }
1958 spec
1959 }
1960
1961 pub fn to_str(self) -> &'static str {
1962 match self {
1963 Bug | DelayedBug => "error: internal compiler error",
1964 Fatal | Error => "error",
1965 ForceWarning(_) | Warning => "warning",
1966 Note | OnceNote => "note",
1967 Help | OnceHelp => "help",
1968 FailureNote => "failure-note",
1969 Allow | Expect(_) => unreachable!(),
1970 }
1971 }
1972
1973 pub fn is_failure_note(&self) -> bool {
1974 matches!(*self, FailureNote)
1975 }
1976
1977 fn can_be_subdiag(&self) -> bool {
1979 match self {
1980 Bug | DelayedBug | Fatal | Error | ForceWarning(_) | FailureNote | Allow
1981 | Expect(_) => false,
1982
1983 Warning | Note | Help | OnceNote | OnceHelp => true,
1984 }
1985 }
1986}
1987
1988pub fn elided_lifetime_in_path_suggestion(
1990 source_map: &SourceMap,
1991 n: usize,
1992 path_span: Span,
1993 incl_angl_brckt: bool,
1994 insertion_span: Span,
1995) -> ElidedLifetimeInPathSubdiag {
1996 let expected = ExpectedLifetimeParameter { span: path_span, count: n };
1997 let indicate = source_map.is_span_accessible(insertion_span).then(|| {
1999 let anon_lts = vec!["'_"; n].join(", ");
2000 let suggestion =
2001 if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
2002
2003 IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
2004 });
2005
2006 ElidedLifetimeInPathSubdiag { expected, indicate }
2007}
2008
2009pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
2010 diag: &mut Diag<'a, G>,
2011 ambiguity: rustc_lint_defs::AmbiguityErrorDiag,
2012) {
2013 diag.span_label(ambiguity.label_span, ambiguity.label_msg);
2014 diag.note(ambiguity.note_msg);
2015 diag.span_note(ambiguity.b1_span, ambiguity.b1_note_msg);
2016 for help_msg in ambiguity.b1_help_msgs {
2017 diag.help(help_msg);
2018 }
2019 diag.span_note(ambiguity.b2_span, ambiguity.b2_note_msg);
2020 for help_msg in ambiguity.b2_help_msgs {
2021 diag.help(help_msg);
2022 }
2023}
2024
2025pub fn a_or_an(s: &str) -> &'static str {
2029 let mut chars = s.chars();
2030 let Some(mut first_alpha_char) = chars.next() else {
2031 return "a";
2032 };
2033 if first_alpha_char == '`' {
2034 let Some(next) = chars.next() else {
2035 return "a";
2036 };
2037 first_alpha_char = next;
2038 }
2039 if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
2040 "an"
2041 } else {
2042 "a"
2043 }
2044}
2045
2046#[derive(Clone, Copy, PartialEq, Hash, Debug)]
2047pub enum TerminalUrl {
2048 No,
2049 Yes,
2050 Auto,
2051}