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_patterns)]
16#![feature(default_field_values)]
17#![feature(error_reporter)]
18#![feature(if_let_guard)]
19#![feature(negative_impls)]
20#![feature(never_type)]
21#![feature(rustc_attrs)]
22#![feature(rustdoc_internals)]
23#![feature(trait_alias)]
24#![feature(try_blocks)]
25#![feature(yeet_expr)]
26extern crate self as rustc_errors;
29
30use std::assert_matches::assert_matches;
31use std::backtrace::{Backtrace, BacktraceStatus};
32use std::borrow::Cow;
33use std::cell::Cell;
34use std::error::Report;
35use std::ffi::OsStr;
36use std::hash::Hash;
37use std::io::Write;
38use std::num::NonZero;
39use std::ops::DerefMut;
40use std::path::{Path, PathBuf};
41use std::{fmt, panic};
42
43use Level::*;
44pub use codes::*;
45pub use diagnostic::{
46 BugAbort, Diag, DiagArg, DiagArgMap, DiagArgName, DiagArgValue, DiagInner, DiagStyledString,
47 Diagnostic, EmissionGuarantee, FatalAbort, IntoDiagArg, LintDiagnostic, StringPart, Subdiag,
48 Subdiagnostic,
49};
50pub use diagnostic_impls::{
51 DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
52 IndicateAnonymousLifetime, SingleLabelManySpans,
53};
54pub use emitter::ColorConfig;
55use emitter::{DynEmitter, Emitter, is_case_difference, is_different};
56use rustc_data_structures::AtomicRef;
57use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
58use rustc_data_structures::stable_hasher::StableHasher;
59use rustc_data_structures::sync::{DynSend, Lock};
60pub use rustc_error_messages::{
61 DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel,
62 SubdiagMessage, fallback_fluent_bundle, fluent_bundle,
63};
64use rustc_hashes::Hash128;
65use rustc_lint_defs::LintExpectationId;
66pub use rustc_lint_defs::{Applicability, listify, pluralize};
67use rustc_macros::{Decodable, Encodable};
68pub use rustc_span::ErrorGuaranteed;
69pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
70use rustc_span::source_map::SourceMap;
71use rustc_span::{BytePos, DUMMY_SP, Loc, Span};
72pub use snippet::Style;
73pub use termcolor::{Color, ColorSpec, WriteColor};
76use tracing::debug;
77
78use crate::registry::Registry;
79
80pub mod annotate_snippet_emitter_writer;
81pub mod codes;
82mod diagnostic;
83mod diagnostic_impls;
84pub mod emitter;
85pub mod error;
86pub mod json;
87mod lock;
88pub mod markdown;
89pub mod registry;
90mod snippet;
91mod styled_buffer;
92#[cfg(test)]
93mod tests;
94pub mod translation;
95
96pub type PResult<'a, T> = Result<T, Diag<'a>>;
97
98rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
99
100#[cfg(target_pointer_width = "64")]
102rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24);
103#[cfg(target_pointer_width = "64")]
104rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24);
105
106#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
107pub enum SuggestionStyle {
108 HideCodeInline,
110 HideCodeAlways,
112 CompletelyHidden,
114 ShowCode,
118 ShowAlways,
120}
121
122impl SuggestionStyle {
123 fn hide_inline(&self) -> bool {
124 !matches!(*self, SuggestionStyle::ShowCode)
125 }
126}
127
128#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
130pub enum Suggestions {
131 Enabled(Vec<CodeSuggestion>),
136 Sealed(Box<[CodeSuggestion]>),
140 Disabled,
144}
145
146impl Suggestions {
147 pub fn unwrap_tag(self) -> Vec<CodeSuggestion> {
149 match self {
150 Suggestions::Enabled(suggestions) => suggestions,
151 Suggestions::Sealed(suggestions) => suggestions.into_vec(),
152 Suggestions::Disabled => Vec::new(),
153 }
154 }
155}
156
157impl Default for Suggestions {
158 fn default() -> Self {
159 Self::Enabled(vec![])
160 }
161}
162
163#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
164pub struct CodeSuggestion {
165 pub substitutions: Vec<Substitution>,
187 pub msg: DiagMessage,
188 pub style: SuggestionStyle,
190 pub applicability: Applicability,
196}
197
198#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
199pub struct Substitution {
201 pub parts: Vec<SubstitutionPart>,
202}
203
204#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
205pub struct SubstitutionPart {
206 pub span: Span,
207 pub snippet: String,
208}
209
210#[derive(Debug, Clone, Copy)]
213pub(crate) struct SubstitutionHighlight {
214 start: usize,
215 end: usize,
216}
217
218impl SubstitutionPart {
219 pub fn is_addition(&self, sm: &SourceMap) -> bool {
220 !self.snippet.is_empty() && !self.replaces_meaningful_content(sm)
221 }
222
223 pub fn is_deletion(&self, sm: &SourceMap) -> bool {
224 self.snippet.trim().is_empty() && self.replaces_meaningful_content(sm)
225 }
226
227 pub fn is_replacement(&self, sm: &SourceMap) -> bool {
228 !self.snippet.is_empty() && self.replaces_meaningful_content(sm)
229 }
230
231 pub fn is_destructive_replacement(&self, sm: &SourceMap) -> bool {
236 self.is_replacement(sm)
237 && !sm
238 .span_to_snippet(self.span)
239 .is_ok_and(|snippet| as_substr(snippet.trim(), self.snippet.trim()).is_some())
240 }
241
242 fn replaces_meaningful_content(&self, sm: &SourceMap) -> bool {
243 sm.span_to_snippet(self.span)
244 .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty())
245 }
246
247 fn trim_trivial_replacements(&mut self, sm: &SourceMap) {
250 if self.snippet.is_empty() {
251 return;
252 }
253 let Ok(snippet) = sm.span_to_snippet(self.span) else {
254 return;
255 };
256
257 if let Some((prefix, substr, suffix)) = as_substr(&snippet, &self.snippet) {
258 self.span = Span::new(
259 self.span.lo() + BytePos(prefix as u32),
260 self.span.hi() - BytePos(suffix as u32),
261 self.span.ctxt(),
262 self.span.parent(),
263 );
264 self.snippet = substr.to_string();
265 }
266 }
267}
268
269fn as_substr<'a>(original: &'a str, suggestion: &'a str) -> Option<(usize, &'a str, usize)> {
274 let common_prefix = original
275 .chars()
276 .zip(suggestion.chars())
277 .take_while(|(c1, c2)| c1 == c2)
278 .map(|(c, _)| c.len_utf8())
279 .sum();
280 let original = &original[common_prefix..];
281 let suggestion = &suggestion[common_prefix..];
282 if suggestion.ends_with(original) {
283 let common_suffix = original.len();
284 Some((common_prefix, &suggestion[..suggestion.len() - original.len()], common_suffix))
285 } else {
286 None
287 }
288}
289
290impl CodeSuggestion {
291 pub(crate) fn splice_lines(
294 &self,
295 sm: &SourceMap,
296 ) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, bool)> {
297 use rustc_span::{CharPos, Pos};
302
303 fn push_trailing(
312 buf: &mut String,
313 line_opt: Option<&Cow<'_, str>>,
314 lo: &Loc,
315 hi_opt: Option<&Loc>,
316 ) -> usize {
317 let mut line_count = 0;
318 let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
321 if let Some(line) = line_opt {
322 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
323 let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
325 match hi_opt {
326 Some(hi) if hi > lo => {
328 line_count = line[lo..hi].matches('\n').count();
330 buf.push_str(&line[lo..hi])
331 }
332 Some(_) => (),
333 None => {
335 line_count = line[lo..].matches('\n').count();
337 buf.push_str(&line[lo..])
338 }
339 }
340 }
341 if hi_opt.is_none() {
343 buf.push('\n');
344 }
345 }
346 line_count
347 }
348
349 assert!(!self.substitutions.is_empty());
350
351 self.substitutions
352 .iter()
353 .filter(|subst| {
354 let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
357 if invalid {
358 debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
359 }
360 !invalid
361 })
362 .cloned()
363 .filter_map(|mut substitution| {
364 substitution.parts.sort_by_key(|part| part.span.lo());
367
368 let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
370 let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
371 let bounding_span = Span::with_root_ctxt(lo, hi);
372 let lines = sm.span_to_lines(bounding_span).ok()?;
374 assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
375
376 if !sm.ensure_source_file_source_present(&lines.file) {
378 return None;
379 }
380
381 let mut highlights = vec![];
382 let sf = &lines.file;
392 let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
393 prev_hi.col = CharPos::from_usize(0);
394 let mut prev_line =
395 lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
396 let mut buf = String::new();
397
398 let mut line_highlight = vec![];
399 let mut acc = 0;
402 let mut only_capitalization = false;
403 for part in &mut substitution.parts {
404 part.trim_trivial_replacements(sm);
408
409 only_capitalization |= is_case_difference(sm, &part.snippet, part.span);
410 let cur_lo = sm.lookup_char_pos(part.span.lo());
411 if prev_hi.line == cur_lo.line {
412 let mut count =
413 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
414 while count > 0 {
415 highlights.push(std::mem::take(&mut line_highlight));
416 acc = 0;
417 count -= 1;
418 }
419 } else {
420 acc = 0;
421 highlights.push(std::mem::take(&mut line_highlight));
422 let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
423 while count > 0 {
424 highlights.push(std::mem::take(&mut line_highlight));
425 count -= 1;
426 }
427 for idx in prev_hi.line..(cur_lo.line - 1) {
429 if let Some(line) = sf.get_line(idx) {
430 buf.push_str(line.as_ref());
431 buf.push('\n');
432 highlights.push(std::mem::take(&mut line_highlight));
433 }
434 }
435 if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
436 let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
437 Some((i, _)) => i,
438 None => cur_line.len(),
439 };
440 buf.push_str(&cur_line[..end]);
441 }
442 }
443 let len: isize = part
445 .snippet
446 .split('\n')
447 .next()
448 .unwrap_or(&part.snippet)
449 .chars()
450 .map(|c| match c {
451 '\t' => 4,
452 _ => 1,
453 })
454 .sum();
455 if !is_different(sm, &part.snippet, part.span) {
456 } else {
460 line_highlight.push(SubstitutionHighlight {
461 start: (cur_lo.col.0 as isize + acc) as usize,
462 end: (cur_lo.col.0 as isize + acc + len) as usize,
463 });
464 }
465 buf.push_str(&part.snippet);
466 let cur_hi = sm.lookup_char_pos(part.span.hi());
467 acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
472 prev_hi = cur_hi;
473 prev_line = sf.get_line(prev_hi.line - 1);
474 for line in part.snippet.split('\n').skip(1) {
475 acc = 0;
476 highlights.push(std::mem::take(&mut line_highlight));
477 let end: usize = line
478 .chars()
479 .map(|c| match c {
480 '\t' => 4,
481 _ => 1,
482 })
483 .sum();
484 line_highlight.push(SubstitutionHighlight { start: 0, end });
485 }
486 }
487 highlights.push(std::mem::take(&mut line_highlight));
488 if !buf.ends_with('\n') {
490 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
491 }
492 while buf.ends_with('\n') {
494 buf.pop();
495 }
496 if highlights.iter().all(|parts| parts.is_empty()) {
497 None
498 } else {
499 Some((buf, substitution.parts, highlights, only_capitalization))
500 }
501 })
502 .collect()
503 }
504}
505
506pub struct ExplicitBug;
509
510pub struct DelayedBugPanic;
513
514pub struct DiagCtxt {
518 inner: Lock<DiagCtxtInner>,
519}
520
521#[derive(Copy, Clone)]
522pub struct DiagCtxtHandle<'a> {
523 dcx: &'a DiagCtxt,
524 tainted_with_errors: Option<&'a Cell<Option<ErrorGuaranteed>>>,
527}
528
529impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
530 type Target = &'a DiagCtxt;
531
532 fn deref(&self) -> &Self::Target {
533 &self.dcx
534 }
535}
536
537struct DiagCtxtInner {
541 flags: DiagCtxtFlags,
542
543 registry: Registry,
544
545 err_guars: Vec<ErrorGuaranteed>,
547 lint_err_guars: Vec<ErrorGuaranteed>,
550 delayed_bugs: Vec<(DelayedDiagInner, ErrorGuaranteed)>,
552
553 deduplicated_err_count: usize,
555 deduplicated_warn_count: usize,
557
558 emitter: Box<DynEmitter>,
559
560 must_produce_diag: Option<Backtrace>,
563
564 has_printed: bool,
567
568 suppressed_expected_diag: bool,
571
572 taught_diagnostics: FxHashSet<ErrCode>,
576
577 emitted_diagnostic_codes: FxIndexSet<ErrCode>,
579
580 emitted_diagnostics: FxHashSet<Hash128>,
584
585 stashed_diagnostics:
591 FxIndexMap<StashKey, FxIndexMap<Span, (DiagInner, Option<ErrorGuaranteed>)>>,
592
593 future_breakage_diagnostics: Vec<DiagInner>,
594
595 fulfilled_expectations: FxIndexSet<LintExpectationId>,
607
608 ice_file: Option<PathBuf>,
611}
612
613#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
615pub enum StashKey {
616 ItemNoType,
617 UnderscoreForArrayLengths,
618 EarlySyntaxWarning,
619 CallIntoMethod,
620 LifetimeIsChar,
623 MaybeFruTypo,
626 CallAssocMethod,
627 AssociatedTypeSuggestion,
628 Cycle,
630 UndeterminedMacroResolution,
631 ExprInPat,
633 GenericInFieldExpr,
637}
638
639fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
640 (*f)(diag)
641}
642
643pub static TRACK_DIAGNOSTIC: AtomicRef<
646 fn(DiagInner, &mut dyn FnMut(DiagInner) -> Option<ErrorGuaranteed>) -> Option<ErrorGuaranteed>,
647> = AtomicRef::new(&(default_track_diagnostic as _));
648
649#[derive(Copy, Clone, Default)]
650pub struct DiagCtxtFlags {
651 pub can_emit_warnings: bool,
654 pub treat_err_as_bug: Option<NonZero<usize>>,
657 pub eagerly_emit_delayed_bugs: bool,
660 pub macro_backtrace: bool,
663 pub deduplicate_diagnostics: bool,
665 pub track_diagnostics: bool,
667}
668
669impl Drop for DiagCtxtInner {
670 fn drop(&mut self) {
671 self.emit_stashed_diagnostics();
679
680 self.flush_delayed();
684
685 if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
689 if let Some(backtrace) = &self.must_produce_diag {
690 let suggestion = match backtrace.status() {
691 BacktraceStatus::Disabled => String::from(
692 "Backtraces are currently disabled: set `RUST_BACKTRACE=1` and re-run \
693 to see where it happened.",
694 ),
695 BacktraceStatus::Captured => format!(
696 "This happened in the following `must_produce_diag` call's backtrace:\n\
697 {backtrace}",
698 ),
699 _ => String::from("(impossible to capture backtrace where this happened)"),
700 };
701 panic!(
702 "`trimmed_def_paths` called, diagnostics were expected but none were emitted. \
703 Use `with_no_trimmed_paths` for debugging. {suggestion}"
704 );
705 }
706 }
707 }
708}
709
710impl DiagCtxt {
711 pub fn disable_warnings(mut self) -> Self {
712 self.inner.get_mut().flags.can_emit_warnings = false;
713 self
714 }
715
716 pub fn with_flags(mut self, flags: DiagCtxtFlags) -> Self {
717 self.inner.get_mut().flags = flags;
718 self
719 }
720
721 pub fn with_ice_file(mut self, ice_file: PathBuf) -> Self {
722 self.inner.get_mut().ice_file = Some(ice_file);
723 self
724 }
725
726 pub fn with_registry(mut self, registry: Registry) -> Self {
727 self.inner.get_mut().registry = registry;
728 self
729 }
730
731 pub fn new(emitter: Box<DynEmitter>) -> Self {
732 Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
733 }
734
735 pub fn make_silent(&self, fatal_note: Option<String>, emit_fatal_diagnostic: bool) {
736 struct FalseEmitter;
739
740 impl Emitter for FalseEmitter {
741 fn emit_diagnostic(&mut self, _: DiagInner, _: &Registry) {
742 unimplemented!("false emitter must only used during `make_silent`")
743 }
744
745 fn source_map(&self) -> Option<&SourceMap> {
746 unimplemented!("false emitter must only used during `make_silent`")
747 }
748 }
749
750 impl translation::Translate for FalseEmitter {
751 fn fluent_bundle(&self) -> Option<&FluentBundle> {
752 unimplemented!("false emitter must only used during `make_silent`")
753 }
754
755 fn fallback_fluent_bundle(&self) -> &FluentBundle {
756 unimplemented!("false emitter must only used during `make_silent`")
757 }
758 }
759
760 let mut inner = self.inner.borrow_mut();
761 let mut prev_emitter = Box::new(FalseEmitter) as Box<dyn Emitter + DynSend>;
762 std::mem::swap(&mut inner.emitter, &mut prev_emitter);
763 let new_emitter = Box::new(emitter::SilentEmitter {
764 fatal_emitter: prev_emitter,
765 fatal_note,
766 emit_fatal_diagnostic,
767 });
768 inner.emitter = new_emitter;
769 }
770
771 pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) {
772 self.inner.borrow_mut().emitter = emitter;
773 }
774
775 pub fn eagerly_translate<'a>(
777 &self,
778 message: DiagMessage,
779 args: impl Iterator<Item = DiagArg<'a>>,
780 ) -> SubdiagMessage {
781 let inner = self.inner.borrow();
782 inner.eagerly_translate(message, args)
783 }
784
785 pub fn eagerly_translate_to_string<'a>(
787 &self,
788 message: DiagMessage,
789 args: impl Iterator<Item = DiagArg<'a>>,
790 ) -> String {
791 let inner = self.inner.borrow();
792 inner.eagerly_translate_to_string(message, args)
793 }
794
795 pub fn can_emit_warnings(&self) -> bool {
799 self.inner.borrow_mut().flags.can_emit_warnings
800 }
801
802 pub fn reset_err_count(&self) {
808 let mut inner = self.inner.borrow_mut();
811 let DiagCtxtInner {
812 flags: _,
813 registry: _,
814 err_guars,
815 lint_err_guars,
816 delayed_bugs,
817 deduplicated_err_count,
818 deduplicated_warn_count,
819 emitter: _,
820 must_produce_diag,
821 has_printed,
822 suppressed_expected_diag,
823 taught_diagnostics,
824 emitted_diagnostic_codes,
825 emitted_diagnostics,
826 stashed_diagnostics,
827 future_breakage_diagnostics,
828 fulfilled_expectations,
829 ice_file: _,
830 } = inner.deref_mut();
831
832 *err_guars = Default::default();
835 *lint_err_guars = Default::default();
836 *delayed_bugs = Default::default();
837 *deduplicated_err_count = 0;
838 *deduplicated_warn_count = 0;
839 *must_produce_diag = None;
840 *has_printed = false;
841 *suppressed_expected_diag = false;
842 *taught_diagnostics = Default::default();
843 *emitted_diagnostic_codes = Default::default();
844 *emitted_diagnostics = Default::default();
845 *stashed_diagnostics = Default::default();
846 *future_breakage_diagnostics = Default::default();
847 *fulfilled_expectations = Default::default();
848 }
849
850 pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> {
851 DiagCtxtHandle { dcx: self, tainted_with_errors: None }
852 }
853
854 pub fn taintable_handle<'a>(
858 &'a self,
859 tainted_with_errors: &'a Cell<Option<ErrorGuaranteed>>,
860 ) -> DiagCtxtHandle<'a> {
861 DiagCtxtHandle { dcx: self, tainted_with_errors: Some(tainted_with_errors) }
862 }
863}
864
865impl<'a> DiagCtxtHandle<'a> {
866 pub fn stash_diagnostic(
888 &self,
889 span: Span,
890 key: StashKey,
891 diag: DiagInner,
892 ) -> Option<ErrorGuaranteed> {
893 let guar = match diag.level {
894 Bug | Fatal => {
895 self.span_bug(
896 span,
897 format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
898 );
899 }
900 Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
904 DelayedBug => {
905 return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors);
906 }
907 ForceWarning | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
908 | Expect => None,
909 };
910
911 self.inner
915 .borrow_mut()
916 .stashed_diagnostics
917 .entry(key)
918 .or_default()
919 .insert(span.with_parent(None), (diag, guar));
920
921 guar
922 }
923
924 pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
928 let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
930 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
931 )?;
932 assert!(!diag.is_error());
933 assert!(guar.is_none());
934 Some(Diag::new_diagnostic(self, diag))
935 }
936
937 pub fn try_steal_modify_and_emit_err<F>(
942 self,
943 span: Span,
944 key: StashKey,
945 mut modify_err: F,
946 ) -> Option<ErrorGuaranteed>
947 where
948 F: FnMut(&mut Diag<'_>),
949 {
950 let err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
952 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
953 );
954 err.map(|(err, guar)| {
955 assert_eq!(err.level, Error);
957 assert!(guar.is_some());
958 let mut err = Diag::<ErrorGuaranteed>::new_diagnostic(self, err);
959 modify_err(&mut err);
960 assert_eq!(err.level, Error);
961 err.emit()
962 })
963 }
964
965 pub fn try_steal_replace_and_emit_err(
969 self,
970 span: Span,
971 key: StashKey,
972 new_err: Diag<'_>,
973 ) -> ErrorGuaranteed {
974 let old_err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
976 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
977 );
978 match old_err {
979 Some((old_err, guar)) => {
980 assert_eq!(old_err.level, Error);
981 assert!(guar.is_some());
982 Diag::<ErrorGuaranteed>::new_diagnostic(self, old_err).cancel();
985 }
986 None => {}
987 };
988 new_err.emit()
989 }
990
991 pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
992 let inner = self.inner.borrow();
993 if let Some(stashed_diagnostics) = inner.stashed_diagnostics.get(&key)
994 && !stashed_diagnostics.is_empty()
995 {
996 stashed_diagnostics.contains_key(&span.with_parent(None))
997 } else {
998 false
999 }
1000 }
1001
1002 pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
1004 self.inner.borrow_mut().emit_stashed_diagnostics()
1005 }
1006
1007 #[inline]
1009 pub fn err_count(&self) -> usize {
1010 let inner = self.inner.borrow();
1011 inner.err_guars.len()
1012 + inner.lint_err_guars.len()
1013 + inner
1014 .stashed_diagnostics
1015 .values()
1016 .map(|a| a.values().filter(|(_, guar)| guar.is_some()).count())
1017 .sum::<usize>()
1018 }
1019
1020 pub fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1023 self.inner.borrow().has_errors_excluding_lint_errors()
1024 }
1025
1026 pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
1028 self.inner.borrow().has_errors()
1029 }
1030
1031 pub fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1034 self.inner.borrow().has_errors_or_delayed_bugs()
1035 }
1036
1037 pub fn print_error_count(&self) {
1038 let mut inner = self.inner.borrow_mut();
1039
1040 assert!(inner.stashed_diagnostics.is_empty());
1043
1044 if inner.treat_err_as_bug() {
1045 return;
1046 }
1047
1048 let warnings = match inner.deduplicated_warn_count {
1049 0 => Cow::from(""),
1050 1 => Cow::from("1 warning emitted"),
1051 count => Cow::from(format!("{count} warnings emitted")),
1052 };
1053 let errors = match inner.deduplicated_err_count {
1054 0 => Cow::from(""),
1055 1 => Cow::from("aborting due to 1 previous error"),
1056 count => Cow::from(format!("aborting due to {count} previous errors")),
1057 };
1058
1059 match (errors.len(), warnings.len()) {
1060 (0, 0) => return,
1061 (0, _) => {
1062 inner.emit_diagnostic(
1065 DiagInner::new(ForceWarning, DiagMessage::Str(warnings)),
1066 None,
1067 );
1068 }
1069 (_, 0) => {
1070 inner.emit_diagnostic(DiagInner::new(Error, errors), self.tainted_with_errors);
1071 }
1072 (_, _) => {
1073 inner.emit_diagnostic(
1074 DiagInner::new(Error, format!("{errors}; {warnings}")),
1075 self.tainted_with_errors,
1076 );
1077 }
1078 }
1079
1080 let can_show_explain = inner.emitter.should_show_explain();
1081 let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty();
1082 if can_show_explain && are_there_diagnostics {
1083 let mut error_codes = inner
1084 .emitted_diagnostic_codes
1085 .iter()
1086 .filter_map(|&code| {
1087 if inner.registry.try_find_description(code).is_ok() {
1088 Some(code.to_string())
1089 } else {
1090 None
1091 }
1092 })
1093 .collect::<Vec<_>>();
1094 if !error_codes.is_empty() {
1095 error_codes.sort();
1096 if error_codes.len() > 1 {
1097 let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
1098 let msg1 = format!(
1099 "Some errors have detailed explanations: {}{}",
1100 error_codes[..limit].join(", "),
1101 if error_codes.len() > 9 { "..." } else { "." }
1102 );
1103 let msg2 = format!(
1104 "For more information about an error, try `rustc --explain {}`.",
1105 &error_codes[0]
1106 );
1107 inner.emit_diagnostic(DiagInner::new(FailureNote, msg1), None);
1108 inner.emit_diagnostic(DiagInner::new(FailureNote, msg2), None);
1109 } else {
1110 let msg = format!(
1111 "For more information about this error, try `rustc --explain {}`.",
1112 &error_codes[0]
1113 );
1114 inner.emit_diagnostic(DiagInner::new(FailureNote, msg), None);
1115 }
1116 }
1117 }
1118 }
1119
1120 pub fn abort_if_errors(&self) {
1125 if let Some(guar) = self.has_errors() {
1126 guar.raise_fatal();
1127 }
1128 }
1129
1130 pub fn must_teach(&self, code: ErrCode) -> bool {
1136 self.inner.borrow_mut().taught_diagnostics.insert(code)
1137 }
1138
1139 pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
1140 self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors)
1141 }
1142
1143 pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
1144 self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
1145 }
1146
1147 pub fn emit_future_breakage_report(&self) {
1148 let inner = &mut *self.inner.borrow_mut();
1149 let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
1150 if !diags.is_empty() {
1151 inner.emitter.emit_future_breakage_report(diags, &inner.registry);
1152 }
1153 }
1154
1155 pub fn emit_unused_externs(
1156 &self,
1157 lint_level: rustc_lint_defs::Level,
1158 loud: bool,
1159 unused_externs: &[&str],
1160 ) {
1161 let mut inner = self.inner.borrow_mut();
1162
1163 if loud && lint_level.is_error() {
1174 #[allow(deprecated)]
1177 inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
1178 inner.panic_if_treat_err_as_bug();
1179 }
1180
1181 inner.emitter.emit_unused_externs(lint_level, unused_externs)
1182 }
1183
1184 #[must_use]
1187 pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
1188 std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
1189 }
1190
1191 pub fn flush_delayed(&self) {
1192 self.inner.borrow_mut().flush_delayed();
1193 }
1194
1195 #[track_caller]
1198 pub fn set_must_produce_diag(&self) {
1199 assert!(
1200 self.inner.borrow().must_produce_diag.is_none(),
1201 "should only need to collect a backtrace once"
1202 );
1203 self.inner.borrow_mut().must_produce_diag = Some(Backtrace::capture());
1204 }
1205}
1206
1207impl<'a> DiagCtxtHandle<'a> {
1212 #[track_caller]
1215 pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> {
1216 Diag::new(self, Bug, msg.into())
1217 }
1218
1219 #[track_caller]
1222 pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
1223 self.struct_bug(msg).emit()
1224 }
1225
1226 #[track_caller]
1229 pub fn struct_span_bug(
1230 self,
1231 span: impl Into<MultiSpan>,
1232 msg: impl Into<Cow<'static, str>>,
1233 ) -> Diag<'a, BugAbort> {
1234 self.struct_bug(msg).with_span(span)
1235 }
1236
1237 #[track_caller]
1240 pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
1241 self.struct_span_bug(span, msg.into()).emit()
1242 }
1243
1244 #[track_caller]
1245 pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> {
1246 bug.into_diag(self, Bug)
1247 }
1248
1249 #[track_caller]
1250 pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! {
1251 self.create_bug(bug).emit()
1252 }
1253
1254 #[rustc_lint_diagnostics]
1255 #[track_caller]
1256 pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> {
1257 Diag::new(self, Fatal, msg)
1258 }
1259
1260 #[rustc_lint_diagnostics]
1261 #[track_caller]
1262 pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
1263 self.struct_fatal(msg).emit()
1264 }
1265
1266 #[rustc_lint_diagnostics]
1267 #[track_caller]
1268 pub fn struct_span_fatal(
1269 self,
1270 span: impl Into<MultiSpan>,
1271 msg: impl Into<DiagMessage>,
1272 ) -> Diag<'a, FatalAbort> {
1273 self.struct_fatal(msg).with_span(span)
1274 }
1275
1276 #[rustc_lint_diagnostics]
1277 #[track_caller]
1278 pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
1279 self.struct_span_fatal(span, msg).emit()
1280 }
1281
1282 #[track_caller]
1283 pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> {
1284 fatal.into_diag(self, Fatal)
1285 }
1286
1287 #[track_caller]
1288 pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
1289 self.create_fatal(fatal).emit()
1290 }
1291
1292 #[track_caller]
1293 pub fn create_almost_fatal(
1294 self,
1295 fatal: impl Diagnostic<'a, FatalError>,
1296 ) -> Diag<'a, FatalError> {
1297 fatal.into_diag(self, Fatal)
1298 }
1299
1300 #[track_caller]
1301 pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError {
1302 self.create_almost_fatal(fatal).emit()
1303 }
1304
1305 #[rustc_lint_diagnostics]
1307 #[track_caller]
1308 pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> {
1309 Diag::new(self, Error, msg)
1310 }
1311
1312 #[rustc_lint_diagnostics]
1313 #[track_caller]
1314 pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
1315 self.struct_err(msg).emit()
1316 }
1317
1318 #[rustc_lint_diagnostics]
1319 #[track_caller]
1320 pub fn struct_span_err(
1321 self,
1322 span: impl Into<MultiSpan>,
1323 msg: impl Into<DiagMessage>,
1324 ) -> Diag<'a> {
1325 self.struct_err(msg).with_span(span)
1326 }
1327
1328 #[rustc_lint_diagnostics]
1329 #[track_caller]
1330 pub fn span_err(
1331 self,
1332 span: impl Into<MultiSpan>,
1333 msg: impl Into<DiagMessage>,
1334 ) -> ErrorGuaranteed {
1335 self.struct_span_err(span, msg).emit()
1336 }
1337
1338 #[track_caller]
1339 pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> {
1340 err.into_diag(self, Error)
1341 }
1342
1343 #[track_caller]
1344 pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
1345 self.create_err(err).emit()
1346 }
1347
1348 #[track_caller]
1353 pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
1354 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
1355 }
1356
1357 #[track_caller]
1365 pub fn span_delayed_bug(
1366 self,
1367 sp: impl Into<MultiSpan>,
1368 msg: impl Into<Cow<'static, str>>,
1369 ) -> ErrorGuaranteed {
1370 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
1371 }
1372
1373 #[rustc_lint_diagnostics]
1374 #[track_caller]
1375 pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1376 Diag::new(self, Warning, msg)
1377 }
1378
1379 #[rustc_lint_diagnostics]
1380 #[track_caller]
1381 pub fn warn(self, msg: impl Into<DiagMessage>) {
1382 self.struct_warn(msg).emit()
1383 }
1384
1385 #[rustc_lint_diagnostics]
1386 #[track_caller]
1387 pub fn struct_span_warn(
1388 self,
1389 span: impl Into<MultiSpan>,
1390 msg: impl Into<DiagMessage>,
1391 ) -> Diag<'a, ()> {
1392 self.struct_warn(msg).with_span(span)
1393 }
1394
1395 #[rustc_lint_diagnostics]
1396 #[track_caller]
1397 pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1398 self.struct_span_warn(span, msg).emit()
1399 }
1400
1401 #[track_caller]
1402 pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1403 warning.into_diag(self, Warning)
1404 }
1405
1406 #[track_caller]
1407 pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) {
1408 self.create_warn(warning).emit()
1409 }
1410
1411 #[rustc_lint_diagnostics]
1412 #[track_caller]
1413 pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1414 Diag::new(self, Note, msg)
1415 }
1416
1417 #[rustc_lint_diagnostics]
1418 #[track_caller]
1419 pub fn note(&self, msg: impl Into<DiagMessage>) {
1420 self.struct_note(msg).emit()
1421 }
1422
1423 #[rustc_lint_diagnostics]
1424 #[track_caller]
1425 pub fn struct_span_note(
1426 self,
1427 span: impl Into<MultiSpan>,
1428 msg: impl Into<DiagMessage>,
1429 ) -> Diag<'a, ()> {
1430 self.struct_note(msg).with_span(span)
1431 }
1432
1433 #[rustc_lint_diagnostics]
1434 #[track_caller]
1435 pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1436 self.struct_span_note(span, msg).emit()
1437 }
1438
1439 #[track_caller]
1440 pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1441 note.into_diag(self, Note)
1442 }
1443
1444 #[track_caller]
1445 pub fn emit_note(self, note: impl Diagnostic<'a, ()>) {
1446 self.create_note(note).emit()
1447 }
1448
1449 #[rustc_lint_diagnostics]
1450 #[track_caller]
1451 pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1452 Diag::new(self, Help, msg)
1453 }
1454
1455 #[rustc_lint_diagnostics]
1456 #[track_caller]
1457 pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1458 Diag::new(self, FailureNote, msg)
1459 }
1460
1461 #[rustc_lint_diagnostics]
1462 #[track_caller]
1463 pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1464 Diag::new(self, Allow, msg)
1465 }
1466
1467 #[rustc_lint_diagnostics]
1468 #[track_caller]
1469 pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> {
1470 Diag::new(self, Expect, msg).with_lint_id(id)
1471 }
1472}
1473
1474impl DiagCtxtInner {
1479 fn new(emitter: Box<DynEmitter>) -> Self {
1480 Self {
1481 flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
1482 registry: Registry::new(&[]),
1483 err_guars: Vec::new(),
1484 lint_err_guars: Vec::new(),
1485 delayed_bugs: Vec::new(),
1486 deduplicated_err_count: 0,
1487 deduplicated_warn_count: 0,
1488 emitter,
1489 must_produce_diag: None,
1490 has_printed: false,
1491 suppressed_expected_diag: false,
1492 taught_diagnostics: Default::default(),
1493 emitted_diagnostic_codes: Default::default(),
1494 emitted_diagnostics: Default::default(),
1495 stashed_diagnostics: Default::default(),
1496 future_breakage_diagnostics: Vec::new(),
1497 fulfilled_expectations: Default::default(),
1498 ice_file: None,
1499 }
1500 }
1501
1502 fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
1504 let mut guar = None;
1505 let has_errors = !self.err_guars.is_empty();
1506 for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
1507 for (_, (diag, _guar)) in stashed_diagnostics {
1508 if !diag.is_error() {
1509 if !diag.is_force_warn() && has_errors {
1513 continue;
1514 }
1515 }
1516 guar = guar.or(self.emit_diagnostic(diag, None));
1517 }
1518 }
1519 guar
1520 }
1521
1522 fn emit_diagnostic(
1524 &mut self,
1525 mut diagnostic: DiagInner,
1526 taint: Option<&Cell<Option<ErrorGuaranteed>>>,
1527 ) -> Option<ErrorGuaranteed> {
1528 if diagnostic.has_future_breakage() {
1529 assert_matches!(diagnostic.level, Error | Warning | Allow | Expect);
1533 self.future_breakage_diagnostics.push(diagnostic.clone());
1534 }
1535
1536 match diagnostic.level {
1540 Bug => {}
1541 Fatal | Error => {
1542 if self.treat_next_err_as_bug() {
1543 diagnostic.level = Bug;
1545 }
1546 }
1547 DelayedBug => {
1548 if self.flags.eagerly_emit_delayed_bugs {
1553 if self.treat_next_err_as_bug() {
1555 diagnostic.level = Bug;
1556 } else {
1557 diagnostic.level = Error;
1558 }
1559 } else {
1560 return if let Some(guar) = self.has_errors() {
1563 Some(guar)
1564 } else {
1565 let backtrace = std::backtrace::Backtrace::capture();
1569 #[allow(deprecated)]
1573 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1574 self.delayed_bugs
1575 .push((DelayedDiagInner::with_backtrace(diagnostic, backtrace), guar));
1576 Some(guar)
1577 };
1578 }
1579 }
1580 ForceWarning if diagnostic.lint_id.is_none() => {} Warning => {
1582 if !self.flags.can_emit_warnings {
1583 if diagnostic.has_future_breakage() {
1585 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1587 }
1588 return None;
1589 }
1590 }
1591 Note | Help | FailureNote => {}
1592 OnceNote | OnceHelp => panic!("bad level: {:?}", diagnostic.level),
1593 Allow => {
1594 if diagnostic.has_future_breakage() {
1596 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1598 self.suppressed_expected_diag = true;
1599 }
1600 return None;
1601 }
1602 Expect | ForceWarning => {
1603 self.fulfilled_expectations.insert(diagnostic.lint_id.unwrap());
1604 if let Expect = diagnostic.level {
1605 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1607 self.suppressed_expected_diag = true;
1608 return None;
1609 }
1610 }
1611 }
1612
1613 TRACK_DIAGNOSTIC(diagnostic, &mut |mut diagnostic| {
1614 if let Some(code) = diagnostic.code {
1615 self.emitted_diagnostic_codes.insert(code);
1616 }
1617
1618 let already_emitted = {
1619 let mut hasher = StableHasher::new();
1620 diagnostic.hash(&mut hasher);
1621 let diagnostic_hash = hasher.finish();
1622 !self.emitted_diagnostics.insert(diagnostic_hash)
1623 };
1624
1625 let is_error = diagnostic.is_error();
1626 let is_lint = diagnostic.is_lint.is_some();
1627
1628 if !(self.flags.deduplicate_diagnostics && already_emitted) {
1631 debug!(?diagnostic);
1632 debug!(?self.emitted_diagnostics);
1633
1634 let not_yet_emitted = |sub: &mut Subdiag| {
1635 debug!(?sub);
1636 if sub.level != OnceNote && sub.level != OnceHelp {
1637 return true;
1638 }
1639 let mut hasher = StableHasher::new();
1640 sub.hash(&mut hasher);
1641 let diagnostic_hash = hasher.finish();
1642 debug!(?diagnostic_hash);
1643 self.emitted_diagnostics.insert(diagnostic_hash)
1644 };
1645 diagnostic.children.retain_mut(not_yet_emitted);
1646 if already_emitted {
1647 let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`";
1648 diagnostic.sub(Note, msg, MultiSpan::new());
1649 }
1650
1651 if is_error {
1652 self.deduplicated_err_count += 1;
1653 } else if matches!(diagnostic.level, ForceWarning | Warning) {
1654 self.deduplicated_warn_count += 1;
1655 }
1656 self.has_printed = true;
1657
1658 self.emitter.emit_diagnostic(diagnostic, &self.registry);
1659 }
1660
1661 if is_error {
1662 if !self.delayed_bugs.is_empty() {
1667 assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0);
1668 self.delayed_bugs.clear();
1669 self.delayed_bugs.shrink_to_fit();
1670 }
1671
1672 #[allow(deprecated)]
1675 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1676 if is_lint {
1677 self.lint_err_guars.push(guar);
1678 } else {
1679 if let Some(taint) = taint {
1680 taint.set(Some(guar));
1681 }
1682 self.err_guars.push(guar);
1683 }
1684 self.panic_if_treat_err_as_bug();
1685 Some(guar)
1686 } else {
1687 None
1688 }
1689 })
1690 }
1691
1692 fn treat_err_as_bug(&self) -> bool {
1693 self.flags
1694 .treat_err_as_bug
1695 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
1696 }
1697
1698 fn treat_next_err_as_bug(&self) -> bool {
1700 self.flags
1701 .treat_err_as_bug
1702 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
1703 }
1704
1705 fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1706 self.err_guars.get(0).copied().or_else(|| {
1707 if let Some((_diag, guar)) = self
1708 .stashed_diagnostics
1709 .values()
1710 .flat_map(|stashed_diagnostics| stashed_diagnostics.values())
1711 .find(|(diag, guar)| guar.is_some() && diag.is_lint.is_none())
1712 {
1713 *guar
1714 } else {
1715 None
1716 }
1717 })
1718 }
1719
1720 fn has_errors(&self) -> Option<ErrorGuaranteed> {
1721 self.err_guars.get(0).copied().or_else(|| self.lint_err_guars.get(0).copied()).or_else(
1722 || {
1723 self.stashed_diagnostics.values().find_map(|stashed_diagnostics| {
1724 stashed_diagnostics.values().find_map(|(_, guar)| *guar)
1725 })
1726 },
1727 )
1728 }
1729
1730 fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1731 self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
1732 }
1733
1734 fn eagerly_translate<'a>(
1736 &self,
1737 message: DiagMessage,
1738 args: impl Iterator<Item = DiagArg<'a>>,
1739 ) -> SubdiagMessage {
1740 SubdiagMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
1741 }
1742
1743 fn eagerly_translate_to_string<'a>(
1745 &self,
1746 message: DiagMessage,
1747 args: impl Iterator<Item = DiagArg<'a>>,
1748 ) -> String {
1749 let args = crate::translation::to_fluent_args(args);
1750 self.emitter.translate_message(&message, &args).map_err(Report::new).unwrap().to_string()
1751 }
1752
1753 fn eagerly_translate_for_subdiag(
1754 &self,
1755 diag: &DiagInner,
1756 msg: impl Into<SubdiagMessage>,
1757 ) -> SubdiagMessage {
1758 let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
1759 self.eagerly_translate(msg, diag.args.iter())
1760 }
1761
1762 fn flush_delayed(&mut self) {
1763 assert!(self.stashed_diagnostics.is_empty());
1767
1768 if !self.err_guars.is_empty() {
1769 return;
1771 }
1772
1773 if self.delayed_bugs.is_empty() {
1774 return;
1776 }
1777
1778 let bugs: Vec<_> =
1779 std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
1780
1781 let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0"));
1782 let decorate = backtrace || self.ice_file.is_none();
1783 let mut out = self
1784 .ice_file
1785 .as_ref()
1786 .and_then(|file| std::fs::File::options().create(true).append(true).open(file).ok());
1787
1788 let note1 = "no errors encountered even though delayed bugs were created";
1793 let note2 = "those delayed bugs will now be shown as internal compiler errors";
1794 self.emit_diagnostic(DiagInner::new(Note, note1), None);
1795 self.emit_diagnostic(DiagInner::new(Note, note2), None);
1796
1797 for bug in bugs {
1798 if let Some(out) = &mut out {
1799 _ = write!(
1800 out,
1801 "delayed bug: {}\n{}\n",
1802 bug.inner
1803 .messages
1804 .iter()
1805 .filter_map(|(msg, _)| msg.as_str())
1806 .collect::<String>(),
1807 &bug.note
1808 );
1809 }
1810
1811 let mut bug = if decorate { bug.decorate(self) } else { bug.inner };
1812
1813 if bug.level != DelayedBug {
1815 bug.arg("level", bug.level);
1822 let msg = crate::fluent_generated::errors_invalid_flushed_delayed_diagnostic_level;
1823 let msg = self.eagerly_translate_for_subdiag(&bug, msg); bug.sub(Note, msg, bug.span.primary_span().unwrap().into());
1825 }
1826 bug.level = Bug;
1827
1828 self.emit_diagnostic(bug, None);
1829 }
1830
1831 panic::panic_any(DelayedBugPanic);
1833 }
1834
1835 fn panic_if_treat_err_as_bug(&self) {
1836 if self.treat_err_as_bug() {
1837 let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
1838 assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
1839 if n == 1 {
1840 panic!("aborting due to `-Z treat-err-as-bug=1`");
1841 } else {
1842 panic!("aborting after {n} errors due to `-Z treat-err-as-bug={n}`");
1843 }
1844 }
1845 }
1846}
1847
1848struct DelayedDiagInner {
1849 inner: DiagInner,
1850 note: Backtrace,
1851}
1852
1853impl DelayedDiagInner {
1854 fn with_backtrace(diagnostic: DiagInner, backtrace: Backtrace) -> Self {
1855 DelayedDiagInner { inner: diagnostic, note: backtrace }
1856 }
1857
1858 fn decorate(self, dcx: &DiagCtxtInner) -> DiagInner {
1859 let mut diag = self.inner;
1863 let msg = match self.note.status() {
1864 BacktraceStatus::Captured => crate::fluent_generated::errors_delayed_at_with_newline,
1865 _ => crate::fluent_generated::errors_delayed_at_without_newline,
1868 };
1869 diag.arg("emitted_at", diag.emitted_at.clone());
1870 diag.arg("note", self.note);
1871 let msg = dcx.eagerly_translate_for_subdiag(&diag, msg); diag.sub(Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into());
1873 diag
1874 }
1875}
1876
1877#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
1897pub enum Level {
1898 Bug,
1900
1901 Fatal,
1904
1905 Error,
1908
1909 DelayedBug,
1914
1915 ForceWarning,
1921
1922 Warning,
1925
1926 Note,
1928
1929 OnceNote,
1931
1932 Help,
1934
1935 OnceHelp,
1937
1938 FailureNote,
1941
1942 Allow,
1944
1945 Expect,
1947}
1948
1949impl fmt::Display for Level {
1950 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1951 self.to_str().fmt(f)
1952 }
1953}
1954
1955impl Level {
1956 fn color(self) -> ColorSpec {
1957 let mut spec = ColorSpec::new();
1958 match self {
1959 Bug | Fatal | Error | DelayedBug => {
1960 spec.set_fg(Some(Color::Red)).set_intense(true);
1961 }
1962 ForceWarning | Warning => {
1963 spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
1964 }
1965 Note | OnceNote => {
1966 spec.set_fg(Some(Color::Green)).set_intense(true);
1967 }
1968 Help | OnceHelp => {
1969 spec.set_fg(Some(Color::Cyan)).set_intense(true);
1970 }
1971 FailureNote => {}
1972 Allow | Expect => unreachable!(),
1973 }
1974 spec
1975 }
1976
1977 pub fn to_str(self) -> &'static str {
1978 match self {
1979 Bug | DelayedBug => "error: internal compiler error",
1980 Fatal | Error => "error",
1981 ForceWarning | Warning => "warning",
1982 Note | OnceNote => "note",
1983 Help | OnceHelp => "help",
1984 FailureNote => "failure-note",
1985 Allow | Expect => unreachable!(),
1986 }
1987 }
1988
1989 pub fn is_failure_note(&self) -> bool {
1990 matches!(*self, FailureNote)
1991 }
1992
1993 fn can_be_subdiag(&self) -> bool {
1995 match self {
1996 Bug | DelayedBug | Fatal | Error | ForceWarning | FailureNote | Allow | Expect => false,
1997
1998 Warning | Note | Help | OnceNote | OnceHelp => true,
1999 }
2000 }
2001}
2002
2003pub fn elided_lifetime_in_path_suggestion(
2005 source_map: &SourceMap,
2006 n: usize,
2007 path_span: Span,
2008 incl_angl_brckt: bool,
2009 insertion_span: Span,
2010) -> ElidedLifetimeInPathSubdiag {
2011 let expected = ExpectedLifetimeParameter { span: path_span, count: n };
2012 let indicate = source_map.is_span_accessible(insertion_span).then(|| {
2014 let anon_lts = vec!["'_"; n].join(", ");
2015 let suggestion =
2016 if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
2017
2018 IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
2019 });
2020
2021 ElidedLifetimeInPathSubdiag { expected, indicate }
2022}
2023
2024pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
2025 diag: &mut Diag<'a, G>,
2026 ambiguity: rustc_lint_defs::AmbiguityErrorDiag,
2027) {
2028 diag.span_label(ambiguity.label_span, ambiguity.label_msg);
2029 diag.note(ambiguity.note_msg);
2030 diag.span_note(ambiguity.b1_span, ambiguity.b1_note_msg);
2031 for help_msg in ambiguity.b1_help_msgs {
2032 diag.help(help_msg);
2033 }
2034 diag.span_note(ambiguity.b2_span, ambiguity.b2_note_msg);
2035 for help_msg in ambiguity.b2_help_msgs {
2036 diag.help(help_msg);
2037 }
2038}
2039
2040pub fn a_or_an(s: &str) -> &'static str {
2044 let mut chars = s.chars();
2045 let Some(mut first_alpha_char) = chars.next() else {
2046 return "a";
2047 };
2048 if first_alpha_char == '`' {
2049 let Some(next) = chars.next() else {
2050 return "a";
2051 };
2052 first_alpha_char = next;
2053 }
2054 if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
2055 "an"
2056 } else {
2057 "a"
2058 }
2059}
2060
2061#[derive(Clone, Copy, PartialEq, Hash, Debug)]
2062pub enum TerminalUrl {
2063 No,
2064 Yes,
2065 Auto,
2066}