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