1#![allow(incomplete_features)]
7#![allow(internal_features)]
8#![allow(rustc::diagnostic_outside_of_impl)]
9#![allow(rustc::untranslatable_diagnostic)]
10#![cfg_attr(not(bootstrap), allow(rustc::direct_use_of_rustc_type_ir))]
11#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
12#![doc(rust_logo)]
13#![feature(array_windows)]
14#![feature(assert_matches)]
15#![feature(associated_type_defaults)]
16#![feature(box_patterns)]
17#![feature(default_field_values)]
18#![feature(error_reporter)]
19#![feature(negative_impls)]
20#![feature(never_type)]
21#![feature(rustc_attrs)]
22#![feature(rustdoc_internals)]
23#![feature(try_blocks)]
24#![feature(yeet_expr)]
25extern crate self as rustc_errors;
28
29use std::assert_matches::assert_matches;
30use std::backtrace::{Backtrace, BacktraceStatus};
31use std::borrow::Cow;
32use std::cell::Cell;
33use std::error::Report;
34use std::ffi::OsStr;
35use std::hash::Hash;
36use std::io::Write;
37use std::num::NonZero;
38use std::ops::DerefMut;
39use std::path::{Path, PathBuf};
40use std::{fmt, panic};
41
42use Level::*;
43pub use codes::*;
44pub use diagnostic::{
45 BugAbort, Diag, DiagArg, DiagArgMap, DiagArgName, DiagArgValue, DiagInner, DiagStyledString,
46 Diagnostic, EmissionGuarantee, FatalAbort, IntoDiagArg, LintDiagnostic, StringPart, Subdiag,
47 Subdiagnostic,
48};
49pub use diagnostic_impls::{
50 DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
51 IndicateAnonymousLifetime, SingleLabelManySpans,
52};
53pub use emitter::ColorConfig;
54use emitter::{DynEmitter, Emitter, is_case_difference, is_different};
55use rustc_data_structures::AtomicRef;
56use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
57use rustc_data_structures::stable_hasher::StableHasher;
58use rustc_data_structures::sync::{DynSend, Lock};
59pub use rustc_error_messages::{
60 DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel,
61 SubdiagMessage, fallback_fluent_bundle, fluent_bundle,
62};
63use rustc_hashes::Hash128;
64use rustc_hir::HirId;
65pub use rustc_lint_defs::{Applicability, listify, pluralize};
66use rustc_lint_defs::{Lint, LintExpectationId};
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::emitter::TimingEvent;
79use crate::registry::Registry;
80use crate::timings::TimingRecord;
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 timings;
97pub mod translation;
98
99pub type PResult<'a, T> = Result<T, Diag<'a>>;
100
101rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
102
103#[cfg(target_pointer_width = "64")]
105rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24);
106#[cfg(target_pointer_width = "64")]
107rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24);
108
109pub trait LintEmitter: Copy {
112 #[track_caller]
113 fn emit_node_span_lint(
114 self,
115 lint: &'static Lint,
116 hir_id: HirId,
117 span: impl Into<MultiSpan>,
118 decorator: impl for<'a> LintDiagnostic<'a, ()>,
119 );
120}
121
122#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
123pub enum SuggestionStyle {
124 HideCodeInline,
126 HideCodeAlways,
128 CompletelyHidden,
130 ShowCode,
134 ShowAlways,
136}
137
138impl SuggestionStyle {
139 fn hide_inline(&self) -> bool {
140 !matches!(*self, SuggestionStyle::ShowCode)
141 }
142}
143
144#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
146pub enum Suggestions {
147 Enabled(Vec<CodeSuggestion>),
152 Sealed(Box<[CodeSuggestion]>),
156 Disabled,
160}
161
162impl Suggestions {
163 pub fn unwrap_tag(self) -> Vec<CodeSuggestion> {
165 match self {
166 Suggestions::Enabled(suggestions) => suggestions,
167 Suggestions::Sealed(suggestions) => suggestions.into_vec(),
168 Suggestions::Disabled => Vec::new(),
169 }
170 }
171}
172
173impl Default for Suggestions {
174 fn default() -> Self {
175 Self::Enabled(vec![])
176 }
177}
178
179#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
180pub struct CodeSuggestion {
181 pub substitutions: Vec<Substitution>,
203 pub msg: DiagMessage,
204 pub style: SuggestionStyle,
206 pub applicability: Applicability,
212}
213
214#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
215pub struct Substitution {
217 pub parts: Vec<SubstitutionPart>,
218}
219
220#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
221pub struct SubstitutionPart {
222 pub span: Span,
223 pub snippet: String,
224}
225
226#[derive(Debug, Clone, Copy)]
229pub(crate) struct SubstitutionHighlight {
230 start: usize,
231 end: usize,
232}
233
234impl SubstitutionPart {
235 pub fn is_addition(&self, sm: &SourceMap) -> bool {
236 !self.snippet.is_empty() && !self.replaces_meaningful_content(sm)
237 }
238
239 pub fn is_deletion(&self, sm: &SourceMap) -> bool {
240 self.snippet.trim().is_empty() && self.replaces_meaningful_content(sm)
241 }
242
243 pub fn is_replacement(&self, sm: &SourceMap) -> bool {
244 !self.snippet.is_empty() && self.replaces_meaningful_content(sm)
245 }
246
247 pub fn is_destructive_replacement(&self, sm: &SourceMap) -> bool {
252 self.is_replacement(sm)
253 && !sm
254 .span_to_snippet(self.span)
255 .is_ok_and(|snippet| as_substr(snippet.trim(), self.snippet.trim()).is_some())
256 }
257
258 fn replaces_meaningful_content(&self, sm: &SourceMap) -> bool {
259 sm.span_to_snippet(self.span)
260 .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty())
261 }
262
263 fn trim_trivial_replacements(&mut self, sm: &SourceMap) {
266 if self.snippet.is_empty() {
267 return;
268 }
269 let Ok(snippet) = sm.span_to_snippet(self.span) else {
270 return;
271 };
272
273 if let Some((prefix, substr, suffix)) = as_substr(&snippet, &self.snippet) {
274 self.span = Span::new(
275 self.span.lo() + BytePos(prefix as u32),
276 self.span.hi() - BytePos(suffix as u32),
277 self.span.ctxt(),
278 self.span.parent(),
279 );
280 self.snippet = substr.to_string();
281 }
282 }
283}
284
285fn as_substr<'a>(original: &'a str, suggestion: &'a str) -> Option<(usize, &'a str, usize)> {
290 let common_prefix = original
291 .chars()
292 .zip(suggestion.chars())
293 .take_while(|(c1, c2)| c1 == c2)
294 .map(|(c, _)| c.len_utf8())
295 .sum();
296 let original = &original[common_prefix..];
297 let suggestion = &suggestion[common_prefix..];
298 if suggestion.ends_with(original) {
299 let common_suffix = original.len();
300 Some((common_prefix, &suggestion[..suggestion.len() - original.len()], common_suffix))
301 } else {
302 None
303 }
304}
305
306impl CodeSuggestion {
307 pub(crate) fn splice_lines(
310 &self,
311 sm: &SourceMap,
312 ) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, bool)> {
313 use rustc_span::{CharPos, Pos};
318
319 fn push_trailing(
328 buf: &mut String,
329 line_opt: Option<&Cow<'_, str>>,
330 lo: &Loc,
331 hi_opt: Option<&Loc>,
332 ) -> usize {
333 let mut line_count = 0;
334 let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
337 if let Some(line) = line_opt {
338 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
339 let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
341 match hi_opt {
342 Some(hi) if hi > lo => {
344 line_count = line[lo..hi].matches('\n').count();
346 buf.push_str(&line[lo..hi])
347 }
348 Some(_) => (),
349 None => {
351 line_count = line[lo..].matches('\n').count();
353 buf.push_str(&line[lo..])
354 }
355 }
356 }
357 if hi_opt.is_none() {
359 buf.push('\n');
360 }
361 }
362 line_count
363 }
364
365 assert!(!self.substitutions.is_empty());
366
367 self.substitutions
368 .iter()
369 .filter(|subst| {
370 let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
373 if invalid {
374 debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
375 }
376 !invalid
377 })
378 .cloned()
379 .filter_map(|mut substitution| {
380 substitution.parts.sort_by_key(|part| part.span.lo());
383
384 let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
386 let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
387 let bounding_span = Span::with_root_ctxt(lo, hi);
388 let lines = sm.span_to_lines(bounding_span).ok()?;
390 assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
391
392 if !sm.ensure_source_file_source_present(&lines.file) {
394 return None;
395 }
396
397 let mut highlights = vec![];
398 let sf = &lines.file;
408 let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
409 prev_hi.col = CharPos::from_usize(0);
410 let mut prev_line =
411 lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
412 let mut buf = String::new();
413
414 let mut line_highlight = vec![];
415 let mut acc = 0;
418 let mut only_capitalization = false;
419 for part in &mut substitution.parts {
420 part.trim_trivial_replacements(sm);
424
425 only_capitalization |= is_case_difference(sm, &part.snippet, part.span);
426 let cur_lo = sm.lookup_char_pos(part.span.lo());
427 if prev_hi.line == cur_lo.line {
428 let mut count =
429 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
430 while count > 0 {
431 highlights.push(std::mem::take(&mut line_highlight));
432 acc = 0;
433 count -= 1;
434 }
435 } else {
436 acc = 0;
437 highlights.push(std::mem::take(&mut line_highlight));
438 let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
439 while count > 0 {
440 highlights.push(std::mem::take(&mut line_highlight));
441 count -= 1;
442 }
443 for idx in prev_hi.line..(cur_lo.line - 1) {
445 if let Some(line) = sf.get_line(idx) {
446 buf.push_str(line.as_ref());
447 buf.push('\n');
448 highlights.push(std::mem::take(&mut line_highlight));
449 }
450 }
451 if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
452 let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
453 Some((i, _)) => i,
454 None => cur_line.len(),
455 };
456 buf.push_str(&cur_line[..end]);
457 }
458 }
459 let len: isize = part
461 .snippet
462 .split('\n')
463 .next()
464 .unwrap_or(&part.snippet)
465 .chars()
466 .map(|c| match c {
467 '\t' => 4,
468 _ => 1,
469 })
470 .sum();
471 if !is_different(sm, &part.snippet, part.span) {
472 } else {
476 line_highlight.push(SubstitutionHighlight {
477 start: (cur_lo.col.0 as isize + acc) as usize,
478 end: (cur_lo.col.0 as isize + acc + len) as usize,
479 });
480 }
481 buf.push_str(&part.snippet);
482 let cur_hi = sm.lookup_char_pos(part.span.hi());
483 acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
488 prev_hi = cur_hi;
489 prev_line = sf.get_line(prev_hi.line - 1);
490 for line in part.snippet.split('\n').skip(1) {
491 acc = 0;
492 highlights.push(std::mem::take(&mut line_highlight));
493 let end: usize = line
494 .chars()
495 .map(|c| match c {
496 '\t' => 4,
497 _ => 1,
498 })
499 .sum();
500 line_highlight.push(SubstitutionHighlight { start: 0, end });
501 }
502 }
503 highlights.push(std::mem::take(&mut line_highlight));
504 if !buf.ends_with('\n') {
506 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
507 }
508 while buf.ends_with('\n') {
510 buf.pop();
511 }
512 if highlights.iter().all(|parts| parts.is_empty()) {
513 None
514 } else {
515 Some((buf, substitution.parts, highlights, only_capitalization))
516 }
517 })
518 .collect()
519 }
520}
521
522pub struct ExplicitBug;
525
526pub struct DelayedBugPanic;
529
530pub struct DiagCtxt {
534 inner: Lock<DiagCtxtInner>,
535}
536
537#[derive(Copy, Clone)]
538pub struct DiagCtxtHandle<'a> {
539 dcx: &'a DiagCtxt,
540 tainted_with_errors: Option<&'a Cell<Option<ErrorGuaranteed>>>,
543}
544
545impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
546 type Target = &'a DiagCtxt;
547
548 fn deref(&self) -> &Self::Target {
549 &self.dcx
550 }
551}
552
553struct DiagCtxtInner {
557 flags: DiagCtxtFlags,
558
559 registry: Registry,
560
561 err_guars: Vec<ErrorGuaranteed>,
563 lint_err_guars: Vec<ErrorGuaranteed>,
566 delayed_bugs: Vec<(DelayedDiagInner, ErrorGuaranteed)>,
568
569 deduplicated_err_count: usize,
571 deduplicated_warn_count: usize,
573
574 emitter: Box<DynEmitter>,
575
576 must_produce_diag: Option<Backtrace>,
579
580 has_printed: bool,
583
584 suppressed_expected_diag: bool,
587
588 taught_diagnostics: FxHashSet<ErrCode>,
592
593 emitted_diagnostic_codes: FxIndexSet<ErrCode>,
595
596 emitted_diagnostics: FxHashSet<Hash128>,
600
601 stashed_diagnostics:
607 FxIndexMap<StashKey, FxIndexMap<Span, (DiagInner, Option<ErrorGuaranteed>)>>,
608
609 future_breakage_diagnostics: Vec<DiagInner>,
610
611 fulfilled_expectations: FxIndexSet<LintExpectationId>,
623
624 ice_file: Option<PathBuf>,
627}
628
629#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
631pub enum StashKey {
632 ItemNoType,
633 UnderscoreForArrayLengths,
634 EarlySyntaxWarning,
635 CallIntoMethod,
636 LifetimeIsChar,
639 MaybeFruTypo,
642 CallAssocMethod,
643 AssociatedTypeSuggestion,
644 Cycle,
646 UndeterminedMacroResolution,
647 ExprInPat,
649 GenericInFieldExpr,
653}
654
655fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
656 (*f)(diag)
657}
658
659pub static TRACK_DIAGNOSTIC: AtomicRef<
662 fn(DiagInner, &mut dyn FnMut(DiagInner) -> Option<ErrorGuaranteed>) -> Option<ErrorGuaranteed>,
663> = AtomicRef::new(&(default_track_diagnostic as _));
664
665#[derive(Copy, Clone, Default)]
666pub struct DiagCtxtFlags {
667 pub can_emit_warnings: bool,
670 pub treat_err_as_bug: Option<NonZero<usize>>,
673 pub eagerly_emit_delayed_bugs: bool,
676 pub macro_backtrace: bool,
679 pub deduplicate_diagnostics: bool,
681 pub track_diagnostics: bool,
683}
684
685impl Drop for DiagCtxtInner {
686 fn drop(&mut self) {
687 self.emit_stashed_diagnostics();
695
696 self.flush_delayed();
700
701 if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
705 if let Some(backtrace) = &self.must_produce_diag {
706 let suggestion = match backtrace.status() {
707 BacktraceStatus::Disabled => String::from(
708 "Backtraces are currently disabled: set `RUST_BACKTRACE=1` and re-run \
709 to see where it happened.",
710 ),
711 BacktraceStatus::Captured => format!(
712 "This happened in the following `must_produce_diag` call's backtrace:\n\
713 {backtrace}",
714 ),
715 _ => String::from("(impossible to capture backtrace where this happened)"),
716 };
717 panic!(
718 "`trimmed_def_paths` called, diagnostics were expected but none were emitted. \
719 Use `with_no_trimmed_paths` for debugging. {suggestion}"
720 );
721 }
722 }
723 }
724}
725
726impl DiagCtxt {
727 pub fn disable_warnings(mut self) -> Self {
728 self.inner.get_mut().flags.can_emit_warnings = false;
729 self
730 }
731
732 pub fn with_flags(mut self, flags: DiagCtxtFlags) -> Self {
733 self.inner.get_mut().flags = flags;
734 self
735 }
736
737 pub fn with_ice_file(mut self, ice_file: PathBuf) -> Self {
738 self.inner.get_mut().ice_file = Some(ice_file);
739 self
740 }
741
742 pub fn with_registry(mut self, registry: Registry) -> Self {
743 self.inner.get_mut().registry = registry;
744 self
745 }
746
747 pub fn new(emitter: Box<DynEmitter>) -> Self {
748 Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
749 }
750
751 pub fn make_silent(&self) {
752 let mut inner = self.inner.borrow_mut();
753 let translator = inner.emitter.translator().clone();
754 inner.emitter = Box::new(emitter::SilentEmitter { translator });
755 }
756
757 pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) {
758 self.inner.borrow_mut().emitter = emitter;
759 }
760
761 pub fn eagerly_translate<'a>(
763 &self,
764 message: DiagMessage,
765 args: impl Iterator<Item = DiagArg<'a>>,
766 ) -> SubdiagMessage {
767 let inner = self.inner.borrow();
768 inner.eagerly_translate(message, args)
769 }
770
771 pub fn eagerly_translate_to_string<'a>(
773 &self,
774 message: DiagMessage,
775 args: impl Iterator<Item = DiagArg<'a>>,
776 ) -> String {
777 let inner = self.inner.borrow();
778 inner.eagerly_translate_to_string(message, args)
779 }
780
781 pub fn can_emit_warnings(&self) -> bool {
785 self.inner.borrow_mut().flags.can_emit_warnings
786 }
787
788 pub fn reset_err_count(&self) {
794 let mut inner = self.inner.borrow_mut();
797 let DiagCtxtInner {
798 flags: _,
799 registry: _,
800 err_guars,
801 lint_err_guars,
802 delayed_bugs,
803 deduplicated_err_count,
804 deduplicated_warn_count,
805 emitter: _,
806 must_produce_diag,
807 has_printed,
808 suppressed_expected_diag,
809 taught_diagnostics,
810 emitted_diagnostic_codes,
811 emitted_diagnostics,
812 stashed_diagnostics,
813 future_breakage_diagnostics,
814 fulfilled_expectations,
815 ice_file: _,
816 } = inner.deref_mut();
817
818 *err_guars = Default::default();
821 *lint_err_guars = Default::default();
822 *delayed_bugs = Default::default();
823 *deduplicated_err_count = 0;
824 *deduplicated_warn_count = 0;
825 *must_produce_diag = None;
826 *has_printed = false;
827 *suppressed_expected_diag = false;
828 *taught_diagnostics = Default::default();
829 *emitted_diagnostic_codes = Default::default();
830 *emitted_diagnostics = Default::default();
831 *stashed_diagnostics = Default::default();
832 *future_breakage_diagnostics = Default::default();
833 *fulfilled_expectations = Default::default();
834 }
835
836 pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> {
837 DiagCtxtHandle { dcx: self, tainted_with_errors: None }
838 }
839
840 pub fn taintable_handle<'a>(
844 &'a self,
845 tainted_with_errors: &'a Cell<Option<ErrorGuaranteed>>,
846 ) -> DiagCtxtHandle<'a> {
847 DiagCtxtHandle { dcx: self, tainted_with_errors: Some(tainted_with_errors) }
848 }
849}
850
851impl<'a> DiagCtxtHandle<'a> {
852 pub fn stash_diagnostic(
874 &self,
875 span: Span,
876 key: StashKey,
877 diag: DiagInner,
878 ) -> Option<ErrorGuaranteed> {
879 let guar = match diag.level {
880 Bug | Fatal => {
881 self.span_bug(
882 span,
883 format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
884 );
885 }
886 Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
890 DelayedBug => {
891 return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors);
892 }
893 ForceWarning | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
894 | Expect => None,
895 };
896
897 self.inner
901 .borrow_mut()
902 .stashed_diagnostics
903 .entry(key)
904 .or_default()
905 .insert(span.with_parent(None), (diag, guar));
906
907 guar
908 }
909
910 pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
914 let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
916 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
917 )?;
918 assert!(!diag.is_error());
919 assert!(guar.is_none());
920 Some(Diag::new_diagnostic(self, diag))
921 }
922
923 pub fn try_steal_modify_and_emit_err<F>(
928 self,
929 span: Span,
930 key: StashKey,
931 mut modify_err: F,
932 ) -> Option<ErrorGuaranteed>
933 where
934 F: FnMut(&mut Diag<'_>),
935 {
936 let err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
938 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
939 );
940 err.map(|(err, guar)| {
941 assert_eq!(err.level, Error);
943 assert!(guar.is_some());
944 let mut err = Diag::<ErrorGuaranteed>::new_diagnostic(self, err);
945 modify_err(&mut err);
946 assert_eq!(err.level, Error);
947 err.emit()
948 })
949 }
950
951 pub fn try_steal_replace_and_emit_err(
955 self,
956 span: Span,
957 key: StashKey,
958 new_err: Diag<'_>,
959 ) -> ErrorGuaranteed {
960 let old_err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
962 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
963 );
964 match old_err {
965 Some((old_err, guar)) => {
966 assert_eq!(old_err.level, Error);
967 assert!(guar.is_some());
968 Diag::<ErrorGuaranteed>::new_diagnostic(self, old_err).cancel();
971 }
972 None => {}
973 };
974 new_err.emit()
975 }
976
977 pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
978 let inner = self.inner.borrow();
979 if let Some(stashed_diagnostics) = inner.stashed_diagnostics.get(&key)
980 && !stashed_diagnostics.is_empty()
981 {
982 stashed_diagnostics.contains_key(&span.with_parent(None))
983 } else {
984 false
985 }
986 }
987
988 pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
990 self.inner.borrow_mut().emit_stashed_diagnostics()
991 }
992
993 #[inline]
995 pub fn err_count(&self) -> usize {
996 let inner = self.inner.borrow();
997 inner.err_guars.len()
998 + inner.lint_err_guars.len()
999 + inner
1000 .stashed_diagnostics
1001 .values()
1002 .map(|a| a.values().filter(|(_, guar)| guar.is_some()).count())
1003 .sum::<usize>()
1004 }
1005
1006 pub fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1009 self.inner.borrow().has_errors_excluding_lint_errors()
1010 }
1011
1012 pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
1014 self.inner.borrow().has_errors()
1015 }
1016
1017 pub fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1020 self.inner.borrow().has_errors_or_delayed_bugs()
1021 }
1022
1023 pub fn print_error_count(&self) {
1024 let mut inner = self.inner.borrow_mut();
1025
1026 assert!(inner.stashed_diagnostics.is_empty());
1029
1030 if inner.treat_err_as_bug() {
1031 return;
1032 }
1033
1034 let warnings = match inner.deduplicated_warn_count {
1035 0 => Cow::from(""),
1036 1 => Cow::from("1 warning emitted"),
1037 count => Cow::from(format!("{count} warnings emitted")),
1038 };
1039 let errors = match inner.deduplicated_err_count {
1040 0 => Cow::from(""),
1041 1 => Cow::from("aborting due to 1 previous error"),
1042 count => Cow::from(format!("aborting due to {count} previous errors")),
1043 };
1044
1045 match (errors.len(), warnings.len()) {
1046 (0, 0) => return,
1047 (0, _) => {
1048 inner.emit_diagnostic(
1051 DiagInner::new(ForceWarning, DiagMessage::Str(warnings)),
1052 None,
1053 );
1054 }
1055 (_, 0) => {
1056 inner.emit_diagnostic(DiagInner::new(Error, errors), self.tainted_with_errors);
1057 }
1058 (_, _) => {
1059 inner.emit_diagnostic(
1060 DiagInner::new(Error, format!("{errors}; {warnings}")),
1061 self.tainted_with_errors,
1062 );
1063 }
1064 }
1065
1066 let can_show_explain = inner.emitter.should_show_explain();
1067 let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty();
1068 if can_show_explain && are_there_diagnostics {
1069 let mut error_codes = inner
1070 .emitted_diagnostic_codes
1071 .iter()
1072 .filter_map(|&code| {
1073 if inner.registry.try_find_description(code).is_ok() {
1074 Some(code.to_string())
1075 } else {
1076 None
1077 }
1078 })
1079 .collect::<Vec<_>>();
1080 if !error_codes.is_empty() {
1081 error_codes.sort();
1082 if error_codes.len() > 1 {
1083 let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
1084 let msg1 = format!(
1085 "Some errors have detailed explanations: {}{}",
1086 error_codes[..limit].join(", "),
1087 if error_codes.len() > 9 { "..." } else { "." }
1088 );
1089 let msg2 = format!(
1090 "For more information about an error, try `rustc --explain {}`.",
1091 &error_codes[0]
1092 );
1093 inner.emit_diagnostic(DiagInner::new(FailureNote, msg1), None);
1094 inner.emit_diagnostic(DiagInner::new(FailureNote, msg2), None);
1095 } else {
1096 let msg = format!(
1097 "For more information about this error, try `rustc --explain {}`.",
1098 &error_codes[0]
1099 );
1100 inner.emit_diagnostic(DiagInner::new(FailureNote, msg), None);
1101 }
1102 }
1103 }
1104 }
1105
1106 pub fn abort_if_errors(&self) {
1111 if let Some(guar) = self.has_errors() {
1112 guar.raise_fatal();
1113 }
1114 }
1115
1116 pub fn must_teach(&self, code: ErrCode) -> bool {
1122 self.inner.borrow_mut().taught_diagnostics.insert(code)
1123 }
1124
1125 pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
1126 self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors)
1127 }
1128
1129 pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
1130 self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
1131 }
1132
1133 pub fn emit_timing_section_start(&self, record: TimingRecord) {
1134 self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::Start);
1135 }
1136
1137 pub fn emit_timing_section_end(&self, record: TimingRecord) {
1138 self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::End);
1139 }
1140
1141 pub fn emit_future_breakage_report(&self) {
1142 let inner = &mut *self.inner.borrow_mut();
1143 let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
1144 if !diags.is_empty() {
1145 inner.emitter.emit_future_breakage_report(diags, &inner.registry);
1146 }
1147 }
1148
1149 pub fn emit_unused_externs(
1150 &self,
1151 lint_level: rustc_lint_defs::Level,
1152 loud: bool,
1153 unused_externs: &[&str],
1154 ) {
1155 let mut inner = self.inner.borrow_mut();
1156
1157 if loud && lint_level.is_error() {
1168 #[allow(deprecated)]
1171 inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
1172 inner.panic_if_treat_err_as_bug();
1173 }
1174
1175 inner.emitter.emit_unused_externs(lint_level, unused_externs)
1176 }
1177
1178 #[must_use]
1181 pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
1182 std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
1183 }
1184
1185 pub fn flush_delayed(&self) {
1186 self.inner.borrow_mut().flush_delayed();
1187 }
1188
1189 #[track_caller]
1192 pub fn set_must_produce_diag(&self) {
1193 assert!(
1194 self.inner.borrow().must_produce_diag.is_none(),
1195 "should only need to collect a backtrace once"
1196 );
1197 self.inner.borrow_mut().must_produce_diag = Some(Backtrace::capture());
1198 }
1199}
1200
1201impl<'a> DiagCtxtHandle<'a> {
1206 #[track_caller]
1209 pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> {
1210 Diag::new(self, Bug, msg.into())
1211 }
1212
1213 #[track_caller]
1216 pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
1217 self.struct_bug(msg).emit()
1218 }
1219
1220 #[track_caller]
1223 pub fn struct_span_bug(
1224 self,
1225 span: impl Into<MultiSpan>,
1226 msg: impl Into<Cow<'static, str>>,
1227 ) -> Diag<'a, BugAbort> {
1228 self.struct_bug(msg).with_span(span)
1229 }
1230
1231 #[track_caller]
1234 pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
1235 self.struct_span_bug(span, msg.into()).emit()
1236 }
1237
1238 #[track_caller]
1239 pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> {
1240 bug.into_diag(self, Bug)
1241 }
1242
1243 #[track_caller]
1244 pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! {
1245 self.create_bug(bug).emit()
1246 }
1247
1248 #[rustc_lint_diagnostics]
1249 #[track_caller]
1250 pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> {
1251 Diag::new(self, Fatal, msg)
1252 }
1253
1254 #[rustc_lint_diagnostics]
1255 #[track_caller]
1256 pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
1257 self.struct_fatal(msg).emit()
1258 }
1259
1260 #[rustc_lint_diagnostics]
1261 #[track_caller]
1262 pub fn struct_span_fatal(
1263 self,
1264 span: impl Into<MultiSpan>,
1265 msg: impl Into<DiagMessage>,
1266 ) -> Diag<'a, FatalAbort> {
1267 self.struct_fatal(msg).with_span(span)
1268 }
1269
1270 #[rustc_lint_diagnostics]
1271 #[track_caller]
1272 pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
1273 self.struct_span_fatal(span, msg).emit()
1274 }
1275
1276 #[track_caller]
1277 pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> {
1278 fatal.into_diag(self, Fatal)
1279 }
1280
1281 #[track_caller]
1282 pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
1283 self.create_fatal(fatal).emit()
1284 }
1285
1286 #[track_caller]
1287 pub fn create_almost_fatal(
1288 self,
1289 fatal: impl Diagnostic<'a, FatalError>,
1290 ) -> Diag<'a, FatalError> {
1291 fatal.into_diag(self, Fatal)
1292 }
1293
1294 #[track_caller]
1295 pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError {
1296 self.create_almost_fatal(fatal).emit()
1297 }
1298
1299 #[rustc_lint_diagnostics]
1301 #[track_caller]
1302 pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> {
1303 Diag::new(self, Error, msg)
1304 }
1305
1306 #[rustc_lint_diagnostics]
1307 #[track_caller]
1308 pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
1309 self.struct_err(msg).emit()
1310 }
1311
1312 #[rustc_lint_diagnostics]
1313 #[track_caller]
1314 pub fn struct_span_err(
1315 self,
1316 span: impl Into<MultiSpan>,
1317 msg: impl Into<DiagMessage>,
1318 ) -> Diag<'a> {
1319 self.struct_err(msg).with_span(span)
1320 }
1321
1322 #[rustc_lint_diagnostics]
1323 #[track_caller]
1324 pub fn span_err(
1325 self,
1326 span: impl Into<MultiSpan>,
1327 msg: impl Into<DiagMessage>,
1328 ) -> ErrorGuaranteed {
1329 self.struct_span_err(span, msg).emit()
1330 }
1331
1332 #[track_caller]
1333 pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> {
1334 err.into_diag(self, Error)
1335 }
1336
1337 #[track_caller]
1338 pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
1339 self.create_err(err).emit()
1340 }
1341
1342 #[track_caller]
1347 pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
1348 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
1349 }
1350
1351 #[track_caller]
1359 pub fn span_delayed_bug(
1360 self,
1361 sp: impl Into<MultiSpan>,
1362 msg: impl Into<Cow<'static, str>>,
1363 ) -> ErrorGuaranteed {
1364 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
1365 }
1366
1367 #[rustc_lint_diagnostics]
1368 #[track_caller]
1369 pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1370 Diag::new(self, Warning, msg)
1371 }
1372
1373 #[rustc_lint_diagnostics]
1374 #[track_caller]
1375 pub fn warn(self, msg: impl Into<DiagMessage>) {
1376 self.struct_warn(msg).emit()
1377 }
1378
1379 #[rustc_lint_diagnostics]
1380 #[track_caller]
1381 pub fn struct_span_warn(
1382 self,
1383 span: impl Into<MultiSpan>,
1384 msg: impl Into<DiagMessage>,
1385 ) -> Diag<'a, ()> {
1386 self.struct_warn(msg).with_span(span)
1387 }
1388
1389 #[rustc_lint_diagnostics]
1390 #[track_caller]
1391 pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1392 self.struct_span_warn(span, msg).emit()
1393 }
1394
1395 #[track_caller]
1396 pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1397 warning.into_diag(self, Warning)
1398 }
1399
1400 #[track_caller]
1401 pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) {
1402 self.create_warn(warning).emit()
1403 }
1404
1405 #[rustc_lint_diagnostics]
1406 #[track_caller]
1407 pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1408 Diag::new(self, Note, msg)
1409 }
1410
1411 #[rustc_lint_diagnostics]
1412 #[track_caller]
1413 pub fn note(&self, msg: impl Into<DiagMessage>) {
1414 self.struct_note(msg).emit()
1415 }
1416
1417 #[rustc_lint_diagnostics]
1418 #[track_caller]
1419 pub fn struct_span_note(
1420 self,
1421 span: impl Into<MultiSpan>,
1422 msg: impl Into<DiagMessage>,
1423 ) -> Diag<'a, ()> {
1424 self.struct_note(msg).with_span(span)
1425 }
1426
1427 #[rustc_lint_diagnostics]
1428 #[track_caller]
1429 pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1430 self.struct_span_note(span, msg).emit()
1431 }
1432
1433 #[track_caller]
1434 pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1435 note.into_diag(self, Note)
1436 }
1437
1438 #[track_caller]
1439 pub fn emit_note(self, note: impl Diagnostic<'a, ()>) {
1440 self.create_note(note).emit()
1441 }
1442
1443 #[rustc_lint_diagnostics]
1444 #[track_caller]
1445 pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1446 Diag::new(self, Help, msg)
1447 }
1448
1449 #[rustc_lint_diagnostics]
1450 #[track_caller]
1451 pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1452 Diag::new(self, FailureNote, msg)
1453 }
1454
1455 #[rustc_lint_diagnostics]
1456 #[track_caller]
1457 pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1458 Diag::new(self, Allow, msg)
1459 }
1460
1461 #[rustc_lint_diagnostics]
1462 #[track_caller]
1463 pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> {
1464 Diag::new(self, Expect, msg).with_lint_id(id)
1465 }
1466}
1467
1468impl DiagCtxtInner {
1473 fn new(emitter: Box<DynEmitter>) -> Self {
1474 Self {
1475 flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
1476 registry: Registry::new(&[]),
1477 err_guars: Vec::new(),
1478 lint_err_guars: Vec::new(),
1479 delayed_bugs: Vec::new(),
1480 deduplicated_err_count: 0,
1481 deduplicated_warn_count: 0,
1482 emitter,
1483 must_produce_diag: None,
1484 has_printed: false,
1485 suppressed_expected_diag: false,
1486 taught_diagnostics: Default::default(),
1487 emitted_diagnostic_codes: Default::default(),
1488 emitted_diagnostics: Default::default(),
1489 stashed_diagnostics: Default::default(),
1490 future_breakage_diagnostics: Vec::new(),
1491 fulfilled_expectations: Default::default(),
1492 ice_file: None,
1493 }
1494 }
1495
1496 fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
1498 let mut guar = None;
1499 let has_errors = !self.err_guars.is_empty();
1500 for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
1501 for (_, (diag, _guar)) in stashed_diagnostics {
1502 if !diag.is_error() {
1503 if !diag.is_force_warn() && has_errors {
1507 continue;
1508 }
1509 }
1510 guar = guar.or(self.emit_diagnostic(diag, None));
1511 }
1512 }
1513 guar
1514 }
1515
1516 fn emit_diagnostic(
1518 &mut self,
1519 mut diagnostic: DiagInner,
1520 taint: Option<&Cell<Option<ErrorGuaranteed>>>,
1521 ) -> Option<ErrorGuaranteed> {
1522 if diagnostic.has_future_breakage() {
1523 assert_matches!(diagnostic.level, Error | ForceWarning | Warning | Allow | Expect);
1527 self.future_breakage_diagnostics.push(diagnostic.clone());
1528 }
1529
1530 match diagnostic.level {
1534 Bug => {}
1535 Fatal | Error => {
1536 if self.treat_next_err_as_bug() {
1537 diagnostic.level = Bug;
1539 }
1540 }
1541 DelayedBug => {
1542 if self.flags.eagerly_emit_delayed_bugs {
1547 if self.treat_next_err_as_bug() {
1549 diagnostic.level = Bug;
1550 } else {
1551 diagnostic.level = Error;
1552 }
1553 } else {
1554 return if let Some(guar) = self.has_errors() {
1557 Some(guar)
1558 } else {
1559 let backtrace = std::backtrace::Backtrace::capture();
1563 #[allow(deprecated)]
1567 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1568 self.delayed_bugs
1569 .push((DelayedDiagInner::with_backtrace(diagnostic, backtrace), guar));
1570 Some(guar)
1571 };
1572 }
1573 }
1574 ForceWarning if diagnostic.lint_id.is_none() => {} Warning => {
1576 if !self.flags.can_emit_warnings {
1577 if diagnostic.has_future_breakage() {
1579 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1581 }
1582 return None;
1583 }
1584 }
1585 Note | Help | FailureNote => {}
1586 OnceNote | OnceHelp => panic!("bad level: {:?}", diagnostic.level),
1587 Allow => {
1588 if diagnostic.has_future_breakage() {
1590 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1592 self.suppressed_expected_diag = true;
1593 }
1594 return None;
1595 }
1596 Expect | ForceWarning => {
1597 self.fulfilled_expectations.insert(diagnostic.lint_id.unwrap());
1598 if let Expect = diagnostic.level {
1599 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1601 self.suppressed_expected_diag = true;
1602 return None;
1603 }
1604 }
1605 }
1606
1607 TRACK_DIAGNOSTIC(diagnostic, &mut |mut diagnostic| {
1608 if let Some(code) = diagnostic.code {
1609 self.emitted_diagnostic_codes.insert(code);
1610 }
1611
1612 let already_emitted = {
1613 let mut hasher = StableHasher::new();
1614 diagnostic.hash(&mut hasher);
1615 let diagnostic_hash = hasher.finish();
1616 !self.emitted_diagnostics.insert(diagnostic_hash)
1617 };
1618
1619 let is_error = diagnostic.is_error();
1620 let is_lint = diagnostic.is_lint.is_some();
1621
1622 if !(self.flags.deduplicate_diagnostics && already_emitted) {
1625 debug!(?diagnostic);
1626 debug!(?self.emitted_diagnostics);
1627
1628 let not_yet_emitted = |sub: &mut Subdiag| {
1629 debug!(?sub);
1630 if sub.level != OnceNote && sub.level != OnceHelp {
1631 return true;
1632 }
1633 let mut hasher = StableHasher::new();
1634 sub.hash(&mut hasher);
1635 let diagnostic_hash = hasher.finish();
1636 debug!(?diagnostic_hash);
1637 self.emitted_diagnostics.insert(diagnostic_hash)
1638 };
1639 diagnostic.children.retain_mut(not_yet_emitted);
1640 if already_emitted {
1641 let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`";
1642 diagnostic.sub(Note, msg, MultiSpan::new());
1643 }
1644
1645 if is_error {
1646 self.deduplicated_err_count += 1;
1647 } else if matches!(diagnostic.level, ForceWarning | Warning) {
1648 self.deduplicated_warn_count += 1;
1649 }
1650 self.has_printed = true;
1651
1652 self.emitter.emit_diagnostic(diagnostic, &self.registry);
1653 }
1654
1655 if is_error {
1656 if !self.delayed_bugs.is_empty() {
1661 assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0);
1662 self.delayed_bugs.clear();
1663 self.delayed_bugs.shrink_to_fit();
1664 }
1665
1666 #[allow(deprecated)]
1669 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1670 if is_lint {
1671 self.lint_err_guars.push(guar);
1672 } else {
1673 if let Some(taint) = taint {
1674 taint.set(Some(guar));
1675 }
1676 self.err_guars.push(guar);
1677 }
1678 self.panic_if_treat_err_as_bug();
1679 Some(guar)
1680 } else {
1681 None
1682 }
1683 })
1684 }
1685
1686 fn treat_err_as_bug(&self) -> bool {
1687 self.flags
1688 .treat_err_as_bug
1689 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
1690 }
1691
1692 fn treat_next_err_as_bug(&self) -> bool {
1694 self.flags
1695 .treat_err_as_bug
1696 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
1697 }
1698
1699 fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1700 self.err_guars.get(0).copied().or_else(|| {
1701 if let Some((_diag, guar)) = self
1702 .stashed_diagnostics
1703 .values()
1704 .flat_map(|stashed_diagnostics| stashed_diagnostics.values())
1705 .find(|(diag, guar)| guar.is_some() && diag.is_lint.is_none())
1706 {
1707 *guar
1708 } else {
1709 None
1710 }
1711 })
1712 }
1713
1714 fn has_errors(&self) -> Option<ErrorGuaranteed> {
1715 self.err_guars.get(0).copied().or_else(|| self.lint_err_guars.get(0).copied()).or_else(
1716 || {
1717 self.stashed_diagnostics.values().find_map(|stashed_diagnostics| {
1718 stashed_diagnostics.values().find_map(|(_, guar)| *guar)
1719 })
1720 },
1721 )
1722 }
1723
1724 fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1725 self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
1726 }
1727
1728 fn eagerly_translate<'a>(
1730 &self,
1731 message: DiagMessage,
1732 args: impl Iterator<Item = DiagArg<'a>>,
1733 ) -> SubdiagMessage {
1734 SubdiagMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
1735 }
1736
1737 fn eagerly_translate_to_string<'a>(
1739 &self,
1740 message: DiagMessage,
1741 args: impl Iterator<Item = DiagArg<'a>>,
1742 ) -> String {
1743 let args = crate::translation::to_fluent_args(args);
1744 self.emitter
1745 .translator()
1746 .translate_message(&message, &args)
1747 .map_err(Report::new)
1748 .unwrap()
1749 .to_string()
1750 }
1751
1752 fn eagerly_translate_for_subdiag(
1753 &self,
1754 diag: &DiagInner,
1755 msg: impl Into<SubdiagMessage>,
1756 ) -> SubdiagMessage {
1757 let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
1758 self.eagerly_translate(msg, diag.args.iter())
1759 }
1760
1761 fn flush_delayed(&mut self) {
1762 assert!(self.stashed_diagnostics.is_empty());
1766
1767 if !self.err_guars.is_empty() {
1768 return;
1770 }
1771
1772 if self.delayed_bugs.is_empty() {
1773 return;
1775 }
1776
1777 let bugs: Vec<_> =
1778 std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
1779
1780 let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0"));
1781 let decorate = backtrace || self.ice_file.is_none();
1782 let mut out = self
1783 .ice_file
1784 .as_ref()
1785 .and_then(|file| std::fs::File::options().create(true).append(true).open(file).ok());
1786
1787 let note1 = "no errors encountered even though delayed bugs were created";
1792 let note2 = "those delayed bugs will now be shown as internal compiler errors";
1793 self.emit_diagnostic(DiagInner::new(Note, note1), None);
1794 self.emit_diagnostic(DiagInner::new(Note, note2), None);
1795
1796 for bug in bugs {
1797 if let Some(out) = &mut out {
1798 _ = write!(
1799 out,
1800 "delayed bug: {}\n{}\n",
1801 bug.inner
1802 .messages
1803 .iter()
1804 .filter_map(|(msg, _)| msg.as_str())
1805 .collect::<String>(),
1806 &bug.note
1807 );
1808 }
1809
1810 let mut bug = if decorate { bug.decorate(self) } else { bug.inner };
1811
1812 if bug.level != DelayedBug {
1814 bug.arg("level", bug.level);
1821 let msg = crate::fluent_generated::errors_invalid_flushed_delayed_diagnostic_level;
1822 let msg = self.eagerly_translate_for_subdiag(&bug, msg); bug.sub(Note, msg, bug.span.primary_span().unwrap().into());
1824 }
1825 bug.level = Bug;
1826
1827 self.emit_diagnostic(bug, None);
1828 }
1829
1830 panic::panic_any(DelayedBugPanic);
1832 }
1833
1834 fn panic_if_treat_err_as_bug(&self) {
1835 if self.treat_err_as_bug() {
1836 let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
1837 assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
1838 if n == 1 {
1839 panic!("aborting due to `-Z treat-err-as-bug=1`");
1840 } else {
1841 panic!("aborting after {n} errors due to `-Z treat-err-as-bug={n}`");
1842 }
1843 }
1844 }
1845}
1846
1847struct DelayedDiagInner {
1848 inner: DiagInner,
1849 note: Backtrace,
1850}
1851
1852impl DelayedDiagInner {
1853 fn with_backtrace(diagnostic: DiagInner, backtrace: Backtrace) -> Self {
1854 DelayedDiagInner { inner: diagnostic, note: backtrace }
1855 }
1856
1857 fn decorate(self, dcx: &DiagCtxtInner) -> DiagInner {
1858 let mut diag = self.inner;
1862 let msg = match self.note.status() {
1863 BacktraceStatus::Captured => crate::fluent_generated::errors_delayed_at_with_newline,
1864 _ => crate::fluent_generated::errors_delayed_at_without_newline,
1867 };
1868 diag.arg("emitted_at", diag.emitted_at.clone());
1869 diag.arg("note", self.note);
1870 let msg = dcx.eagerly_translate_for_subdiag(&diag, msg); diag.sub(Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into());
1872 diag
1873 }
1874}
1875
1876#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
1896pub enum Level {
1897 Bug,
1899
1900 Fatal,
1903
1904 Error,
1907
1908 DelayedBug,
1913
1914 ForceWarning,
1920
1921 Warning,
1924
1925 Note,
1927
1928 OnceNote,
1930
1931 Help,
1933
1934 OnceHelp,
1936
1937 FailureNote,
1940
1941 Allow,
1943
1944 Expect,
1946}
1947
1948impl fmt::Display for Level {
1949 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1950 self.to_str().fmt(f)
1951 }
1952}
1953
1954impl Level {
1955 fn color(self) -> ColorSpec {
1956 let mut spec = ColorSpec::new();
1957 match self {
1958 Bug | Fatal | Error | DelayedBug => {
1959 spec.set_fg(Some(Color::Red)).set_intense(true);
1960 }
1961 ForceWarning | Warning => {
1962 spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
1963 }
1964 Note | OnceNote => {
1965 spec.set_fg(Some(Color::Green)).set_intense(true);
1966 }
1967 Help | OnceHelp => {
1968 spec.set_fg(Some(Color::Cyan)).set_intense(true);
1969 }
1970 FailureNote => {}
1971 Allow | Expect => unreachable!(),
1972 }
1973 spec
1974 }
1975
1976 pub fn to_str(self) -> &'static str {
1977 match self {
1978 Bug | DelayedBug => "error: internal compiler error",
1979 Fatal | Error => "error",
1980 ForceWarning | Warning => "warning",
1981 Note | OnceNote => "note",
1982 Help | OnceHelp => "help",
1983 FailureNote => "failure-note",
1984 Allow | Expect => unreachable!(),
1985 }
1986 }
1987
1988 pub fn is_failure_note(&self) -> bool {
1989 matches!(*self, FailureNote)
1990 }
1991
1992 fn can_be_subdiag(&self) -> bool {
1994 match self {
1995 Bug | DelayedBug | Fatal | Error | ForceWarning | FailureNote | Allow | Expect => false,
1996
1997 Warning | Note | Help | OnceNote | OnceHelp => true,
1998 }
1999 }
2000}
2001
2002pub fn elided_lifetime_in_path_suggestion(
2004 source_map: &SourceMap,
2005 n: usize,
2006 path_span: Span,
2007 incl_angl_brckt: bool,
2008 insertion_span: Span,
2009) -> ElidedLifetimeInPathSubdiag {
2010 let expected = ExpectedLifetimeParameter { span: path_span, count: n };
2011 let indicate = source_map.is_span_accessible(insertion_span).then(|| {
2013 let anon_lts = vec!["'_"; n].join(", ");
2014 let suggestion =
2015 if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
2016
2017 IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
2018 });
2019
2020 ElidedLifetimeInPathSubdiag { expected, indicate }
2021}
2022
2023pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
2024 diag: &mut Diag<'a, G>,
2025 ambiguity: rustc_lint_defs::AmbiguityErrorDiag,
2026) {
2027 diag.span_label(ambiguity.label_span, ambiguity.label_msg);
2028 diag.note(ambiguity.note_msg);
2029 diag.span_note(ambiguity.b1_span, ambiguity.b1_note_msg);
2030 for help_msg in ambiguity.b1_help_msgs {
2031 diag.help(help_msg);
2032 }
2033 diag.span_note(ambiguity.b2_span, ambiguity.b2_note_msg);
2034 for help_msg in ambiguity.b2_help_msgs {
2035 diag.help(help_msg);
2036 }
2037}
2038
2039pub fn a_or_an(s: &str) -> &'static str {
2043 let mut chars = s.chars();
2044 let Some(mut first_alpha_char) = chars.next() else {
2045 return "a";
2046 };
2047 if first_alpha_char == '`' {
2048 let Some(next) = chars.next() else {
2049 return "a";
2050 };
2051 first_alpha_char = next;
2052 }
2053 if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
2054 "an"
2055 } else {
2056 "a"
2057 }
2058}
2059
2060#[derive(Clone, Copy, PartialEq, Hash, Debug)]
2061pub enum TerminalUrl {
2062 No,
2063 Yes,
2064 Auto,
2065}