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, fatal_note: Option<String>, emit_fatal_diagnostic: bool) {
752 struct FalseEmitter;
755
756 impl Emitter for FalseEmitter {
757 fn emit_diagnostic(&mut self, _: DiagInner, _: &Registry) {
758 unimplemented!("false emitter must only used during `make_silent`")
759 }
760
761 fn source_map(&self) -> Option<&SourceMap> {
762 unimplemented!("false emitter must only used during `make_silent`")
763 }
764 }
765
766 impl translation::Translate for FalseEmitter {
767 fn fluent_bundle(&self) -> Option<&FluentBundle> {
768 unimplemented!("false emitter must only used during `make_silent`")
769 }
770
771 fn fallback_fluent_bundle(&self) -> &FluentBundle {
772 unimplemented!("false emitter must only used during `make_silent`")
773 }
774 }
775
776 let mut inner = self.inner.borrow_mut();
777 let mut prev_emitter = Box::new(FalseEmitter) as Box<dyn Emitter + DynSend>;
778 std::mem::swap(&mut inner.emitter, &mut prev_emitter);
779 let new_emitter = Box::new(emitter::SilentEmitter {
780 fatal_emitter: prev_emitter,
781 fatal_note,
782 emit_fatal_diagnostic,
783 });
784 inner.emitter = new_emitter;
785 }
786
787 pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) {
788 self.inner.borrow_mut().emitter = emitter;
789 }
790
791 pub fn eagerly_translate<'a>(
793 &self,
794 message: DiagMessage,
795 args: impl Iterator<Item = DiagArg<'a>>,
796 ) -> SubdiagMessage {
797 let inner = self.inner.borrow();
798 inner.eagerly_translate(message, args)
799 }
800
801 pub fn eagerly_translate_to_string<'a>(
803 &self,
804 message: DiagMessage,
805 args: impl Iterator<Item = DiagArg<'a>>,
806 ) -> String {
807 let inner = self.inner.borrow();
808 inner.eagerly_translate_to_string(message, args)
809 }
810
811 pub fn can_emit_warnings(&self) -> bool {
815 self.inner.borrow_mut().flags.can_emit_warnings
816 }
817
818 pub fn reset_err_count(&self) {
824 let mut inner = self.inner.borrow_mut();
827 let DiagCtxtInner {
828 flags: _,
829 registry: _,
830 err_guars,
831 lint_err_guars,
832 delayed_bugs,
833 deduplicated_err_count,
834 deduplicated_warn_count,
835 emitter: _,
836 must_produce_diag,
837 has_printed,
838 suppressed_expected_diag,
839 taught_diagnostics,
840 emitted_diagnostic_codes,
841 emitted_diagnostics,
842 stashed_diagnostics,
843 future_breakage_diagnostics,
844 fulfilled_expectations,
845 ice_file: _,
846 } = inner.deref_mut();
847
848 *err_guars = Default::default();
851 *lint_err_guars = Default::default();
852 *delayed_bugs = Default::default();
853 *deduplicated_err_count = 0;
854 *deduplicated_warn_count = 0;
855 *must_produce_diag = None;
856 *has_printed = false;
857 *suppressed_expected_diag = false;
858 *taught_diagnostics = Default::default();
859 *emitted_diagnostic_codes = Default::default();
860 *emitted_diagnostics = Default::default();
861 *stashed_diagnostics = Default::default();
862 *future_breakage_diagnostics = Default::default();
863 *fulfilled_expectations = Default::default();
864 }
865
866 pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> {
867 DiagCtxtHandle { dcx: self, tainted_with_errors: None }
868 }
869
870 pub fn taintable_handle<'a>(
874 &'a self,
875 tainted_with_errors: &'a Cell<Option<ErrorGuaranteed>>,
876 ) -> DiagCtxtHandle<'a> {
877 DiagCtxtHandle { dcx: self, tainted_with_errors: Some(tainted_with_errors) }
878 }
879}
880
881impl<'a> DiagCtxtHandle<'a> {
882 pub fn stash_diagnostic(
904 &self,
905 span: Span,
906 key: StashKey,
907 diag: DiagInner,
908 ) -> Option<ErrorGuaranteed> {
909 let guar = match diag.level {
910 Bug | Fatal => {
911 self.span_bug(
912 span,
913 format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
914 );
915 }
916 Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
920 DelayedBug => {
921 return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors);
922 }
923 ForceWarning | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
924 | Expect => None,
925 };
926
927 self.inner
931 .borrow_mut()
932 .stashed_diagnostics
933 .entry(key)
934 .or_default()
935 .insert(span.with_parent(None), (diag, guar));
936
937 guar
938 }
939
940 pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
944 let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
946 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
947 )?;
948 assert!(!diag.is_error());
949 assert!(guar.is_none());
950 Some(Diag::new_diagnostic(self, diag))
951 }
952
953 pub fn try_steal_modify_and_emit_err<F>(
958 self,
959 span: Span,
960 key: StashKey,
961 mut modify_err: F,
962 ) -> Option<ErrorGuaranteed>
963 where
964 F: FnMut(&mut Diag<'_>),
965 {
966 let err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
968 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
969 );
970 err.map(|(err, guar)| {
971 assert_eq!(err.level, Error);
973 assert!(guar.is_some());
974 let mut err = Diag::<ErrorGuaranteed>::new_diagnostic(self, err);
975 modify_err(&mut err);
976 assert_eq!(err.level, Error);
977 err.emit()
978 })
979 }
980
981 pub fn try_steal_replace_and_emit_err(
985 self,
986 span: Span,
987 key: StashKey,
988 new_err: Diag<'_>,
989 ) -> ErrorGuaranteed {
990 let old_err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
992 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
993 );
994 match old_err {
995 Some((old_err, guar)) => {
996 assert_eq!(old_err.level, Error);
997 assert!(guar.is_some());
998 Diag::<ErrorGuaranteed>::new_diagnostic(self, old_err).cancel();
1001 }
1002 None => {}
1003 };
1004 new_err.emit()
1005 }
1006
1007 pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
1008 let inner = self.inner.borrow();
1009 if let Some(stashed_diagnostics) = inner.stashed_diagnostics.get(&key)
1010 && !stashed_diagnostics.is_empty()
1011 {
1012 stashed_diagnostics.contains_key(&span.with_parent(None))
1013 } else {
1014 false
1015 }
1016 }
1017
1018 pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
1020 self.inner.borrow_mut().emit_stashed_diagnostics()
1021 }
1022
1023 #[inline]
1025 pub fn err_count(&self) -> usize {
1026 let inner = self.inner.borrow();
1027 inner.err_guars.len()
1028 + inner.lint_err_guars.len()
1029 + inner
1030 .stashed_diagnostics
1031 .values()
1032 .map(|a| a.values().filter(|(_, guar)| guar.is_some()).count())
1033 .sum::<usize>()
1034 }
1035
1036 pub fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1039 self.inner.borrow().has_errors_excluding_lint_errors()
1040 }
1041
1042 pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
1044 self.inner.borrow().has_errors()
1045 }
1046
1047 pub fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1050 self.inner.borrow().has_errors_or_delayed_bugs()
1051 }
1052
1053 pub fn print_error_count(&self) {
1054 let mut inner = self.inner.borrow_mut();
1055
1056 assert!(inner.stashed_diagnostics.is_empty());
1059
1060 if inner.treat_err_as_bug() {
1061 return;
1062 }
1063
1064 let warnings = match inner.deduplicated_warn_count {
1065 0 => Cow::from(""),
1066 1 => Cow::from("1 warning emitted"),
1067 count => Cow::from(format!("{count} warnings emitted")),
1068 };
1069 let errors = match inner.deduplicated_err_count {
1070 0 => Cow::from(""),
1071 1 => Cow::from("aborting due to 1 previous error"),
1072 count => Cow::from(format!("aborting due to {count} previous errors")),
1073 };
1074
1075 match (errors.len(), warnings.len()) {
1076 (0, 0) => return,
1077 (0, _) => {
1078 inner.emit_diagnostic(
1081 DiagInner::new(ForceWarning, DiagMessage::Str(warnings)),
1082 None,
1083 );
1084 }
1085 (_, 0) => {
1086 inner.emit_diagnostic(DiagInner::new(Error, errors), self.tainted_with_errors);
1087 }
1088 (_, _) => {
1089 inner.emit_diagnostic(
1090 DiagInner::new(Error, format!("{errors}; {warnings}")),
1091 self.tainted_with_errors,
1092 );
1093 }
1094 }
1095
1096 let can_show_explain = inner.emitter.should_show_explain();
1097 let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty();
1098 if can_show_explain && are_there_diagnostics {
1099 let mut error_codes = inner
1100 .emitted_diagnostic_codes
1101 .iter()
1102 .filter_map(|&code| {
1103 if inner.registry.try_find_description(code).is_ok() {
1104 Some(code.to_string())
1105 } else {
1106 None
1107 }
1108 })
1109 .collect::<Vec<_>>();
1110 if !error_codes.is_empty() {
1111 error_codes.sort();
1112 if error_codes.len() > 1 {
1113 let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
1114 let msg1 = format!(
1115 "Some errors have detailed explanations: {}{}",
1116 error_codes[..limit].join(", "),
1117 if error_codes.len() > 9 { "..." } else { "." }
1118 );
1119 let msg2 = format!(
1120 "For more information about an error, try `rustc --explain {}`.",
1121 &error_codes[0]
1122 );
1123 inner.emit_diagnostic(DiagInner::new(FailureNote, msg1), None);
1124 inner.emit_diagnostic(DiagInner::new(FailureNote, msg2), None);
1125 } else {
1126 let msg = format!(
1127 "For more information about this error, try `rustc --explain {}`.",
1128 &error_codes[0]
1129 );
1130 inner.emit_diagnostic(DiagInner::new(FailureNote, msg), None);
1131 }
1132 }
1133 }
1134 }
1135
1136 pub fn abort_if_errors(&self) {
1141 if let Some(guar) = self.has_errors() {
1142 guar.raise_fatal();
1143 }
1144 }
1145
1146 pub fn must_teach(&self, code: ErrCode) -> bool {
1152 self.inner.borrow_mut().taught_diagnostics.insert(code)
1153 }
1154
1155 pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
1156 self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors)
1157 }
1158
1159 pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
1160 self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
1161 }
1162
1163 pub fn emit_timing_section_start(&self, record: TimingRecord) {
1164 self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::Start);
1165 }
1166
1167 pub fn emit_timing_section_end(&self, record: TimingRecord) {
1168 self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::End);
1169 }
1170
1171 pub fn emit_future_breakage_report(&self) {
1172 let inner = &mut *self.inner.borrow_mut();
1173 let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
1174 if !diags.is_empty() {
1175 inner.emitter.emit_future_breakage_report(diags, &inner.registry);
1176 }
1177 }
1178
1179 pub fn emit_unused_externs(
1180 &self,
1181 lint_level: rustc_lint_defs::Level,
1182 loud: bool,
1183 unused_externs: &[&str],
1184 ) {
1185 let mut inner = self.inner.borrow_mut();
1186
1187 if loud && lint_level.is_error() {
1198 #[allow(deprecated)]
1201 inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
1202 inner.panic_if_treat_err_as_bug();
1203 }
1204
1205 inner.emitter.emit_unused_externs(lint_level, unused_externs)
1206 }
1207
1208 #[must_use]
1211 pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
1212 std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
1213 }
1214
1215 pub fn flush_delayed(&self) {
1216 self.inner.borrow_mut().flush_delayed();
1217 }
1218
1219 #[track_caller]
1222 pub fn set_must_produce_diag(&self) {
1223 assert!(
1224 self.inner.borrow().must_produce_diag.is_none(),
1225 "should only need to collect a backtrace once"
1226 );
1227 self.inner.borrow_mut().must_produce_diag = Some(Backtrace::capture());
1228 }
1229}
1230
1231impl<'a> DiagCtxtHandle<'a> {
1236 #[track_caller]
1239 pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> {
1240 Diag::new(self, Bug, msg.into())
1241 }
1242
1243 #[track_caller]
1246 pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
1247 self.struct_bug(msg).emit()
1248 }
1249
1250 #[track_caller]
1253 pub fn struct_span_bug(
1254 self,
1255 span: impl Into<MultiSpan>,
1256 msg: impl Into<Cow<'static, str>>,
1257 ) -> Diag<'a, BugAbort> {
1258 self.struct_bug(msg).with_span(span)
1259 }
1260
1261 #[track_caller]
1264 pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
1265 self.struct_span_bug(span, msg.into()).emit()
1266 }
1267
1268 #[track_caller]
1269 pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> {
1270 bug.into_diag(self, Bug)
1271 }
1272
1273 #[track_caller]
1274 pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! {
1275 self.create_bug(bug).emit()
1276 }
1277
1278 #[rustc_lint_diagnostics]
1279 #[track_caller]
1280 pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> {
1281 Diag::new(self, Fatal, msg)
1282 }
1283
1284 #[rustc_lint_diagnostics]
1285 #[track_caller]
1286 pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
1287 self.struct_fatal(msg).emit()
1288 }
1289
1290 #[rustc_lint_diagnostics]
1291 #[track_caller]
1292 pub fn struct_span_fatal(
1293 self,
1294 span: impl Into<MultiSpan>,
1295 msg: impl Into<DiagMessage>,
1296 ) -> Diag<'a, FatalAbort> {
1297 self.struct_fatal(msg).with_span(span)
1298 }
1299
1300 #[rustc_lint_diagnostics]
1301 #[track_caller]
1302 pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
1303 self.struct_span_fatal(span, msg).emit()
1304 }
1305
1306 #[track_caller]
1307 pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> {
1308 fatal.into_diag(self, Fatal)
1309 }
1310
1311 #[track_caller]
1312 pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
1313 self.create_fatal(fatal).emit()
1314 }
1315
1316 #[track_caller]
1317 pub fn create_almost_fatal(
1318 self,
1319 fatal: impl Diagnostic<'a, FatalError>,
1320 ) -> Diag<'a, FatalError> {
1321 fatal.into_diag(self, Fatal)
1322 }
1323
1324 #[track_caller]
1325 pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError {
1326 self.create_almost_fatal(fatal).emit()
1327 }
1328
1329 #[rustc_lint_diagnostics]
1331 #[track_caller]
1332 pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> {
1333 Diag::new(self, Error, msg)
1334 }
1335
1336 #[rustc_lint_diagnostics]
1337 #[track_caller]
1338 pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
1339 self.struct_err(msg).emit()
1340 }
1341
1342 #[rustc_lint_diagnostics]
1343 #[track_caller]
1344 pub fn struct_span_err(
1345 self,
1346 span: impl Into<MultiSpan>,
1347 msg: impl Into<DiagMessage>,
1348 ) -> Diag<'a> {
1349 self.struct_err(msg).with_span(span)
1350 }
1351
1352 #[rustc_lint_diagnostics]
1353 #[track_caller]
1354 pub fn span_err(
1355 self,
1356 span: impl Into<MultiSpan>,
1357 msg: impl Into<DiagMessage>,
1358 ) -> ErrorGuaranteed {
1359 self.struct_span_err(span, msg).emit()
1360 }
1361
1362 #[track_caller]
1363 pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> {
1364 err.into_diag(self, Error)
1365 }
1366
1367 #[track_caller]
1368 pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
1369 self.create_err(err).emit()
1370 }
1371
1372 #[track_caller]
1377 pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
1378 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
1379 }
1380
1381 #[track_caller]
1389 pub fn span_delayed_bug(
1390 self,
1391 sp: impl Into<MultiSpan>,
1392 msg: impl Into<Cow<'static, str>>,
1393 ) -> ErrorGuaranteed {
1394 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
1395 }
1396
1397 #[rustc_lint_diagnostics]
1398 #[track_caller]
1399 pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1400 Diag::new(self, Warning, msg)
1401 }
1402
1403 #[rustc_lint_diagnostics]
1404 #[track_caller]
1405 pub fn warn(self, msg: impl Into<DiagMessage>) {
1406 self.struct_warn(msg).emit()
1407 }
1408
1409 #[rustc_lint_diagnostics]
1410 #[track_caller]
1411 pub fn struct_span_warn(
1412 self,
1413 span: impl Into<MultiSpan>,
1414 msg: impl Into<DiagMessage>,
1415 ) -> Diag<'a, ()> {
1416 self.struct_warn(msg).with_span(span)
1417 }
1418
1419 #[rustc_lint_diagnostics]
1420 #[track_caller]
1421 pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1422 self.struct_span_warn(span, msg).emit()
1423 }
1424
1425 #[track_caller]
1426 pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1427 warning.into_diag(self, Warning)
1428 }
1429
1430 #[track_caller]
1431 pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) {
1432 self.create_warn(warning).emit()
1433 }
1434
1435 #[rustc_lint_diagnostics]
1436 #[track_caller]
1437 pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1438 Diag::new(self, Note, msg)
1439 }
1440
1441 #[rustc_lint_diagnostics]
1442 #[track_caller]
1443 pub fn note(&self, msg: impl Into<DiagMessage>) {
1444 self.struct_note(msg).emit()
1445 }
1446
1447 #[rustc_lint_diagnostics]
1448 #[track_caller]
1449 pub fn struct_span_note(
1450 self,
1451 span: impl Into<MultiSpan>,
1452 msg: impl Into<DiagMessage>,
1453 ) -> Diag<'a, ()> {
1454 self.struct_note(msg).with_span(span)
1455 }
1456
1457 #[rustc_lint_diagnostics]
1458 #[track_caller]
1459 pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1460 self.struct_span_note(span, msg).emit()
1461 }
1462
1463 #[track_caller]
1464 pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1465 note.into_diag(self, Note)
1466 }
1467
1468 #[track_caller]
1469 pub fn emit_note(self, note: impl Diagnostic<'a, ()>) {
1470 self.create_note(note).emit()
1471 }
1472
1473 #[rustc_lint_diagnostics]
1474 #[track_caller]
1475 pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1476 Diag::new(self, Help, msg)
1477 }
1478
1479 #[rustc_lint_diagnostics]
1480 #[track_caller]
1481 pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1482 Diag::new(self, FailureNote, msg)
1483 }
1484
1485 #[rustc_lint_diagnostics]
1486 #[track_caller]
1487 pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1488 Diag::new(self, Allow, msg)
1489 }
1490
1491 #[rustc_lint_diagnostics]
1492 #[track_caller]
1493 pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> {
1494 Diag::new(self, Expect, msg).with_lint_id(id)
1495 }
1496}
1497
1498impl DiagCtxtInner {
1503 fn new(emitter: Box<DynEmitter>) -> Self {
1504 Self {
1505 flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
1506 registry: Registry::new(&[]),
1507 err_guars: Vec::new(),
1508 lint_err_guars: Vec::new(),
1509 delayed_bugs: Vec::new(),
1510 deduplicated_err_count: 0,
1511 deduplicated_warn_count: 0,
1512 emitter,
1513 must_produce_diag: None,
1514 has_printed: false,
1515 suppressed_expected_diag: false,
1516 taught_diagnostics: Default::default(),
1517 emitted_diagnostic_codes: Default::default(),
1518 emitted_diagnostics: Default::default(),
1519 stashed_diagnostics: Default::default(),
1520 future_breakage_diagnostics: Vec::new(),
1521 fulfilled_expectations: Default::default(),
1522 ice_file: None,
1523 }
1524 }
1525
1526 fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
1528 let mut guar = None;
1529 let has_errors = !self.err_guars.is_empty();
1530 for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
1531 for (_, (diag, _guar)) in stashed_diagnostics {
1532 if !diag.is_error() {
1533 if !diag.is_force_warn() && has_errors {
1537 continue;
1538 }
1539 }
1540 guar = guar.or(self.emit_diagnostic(diag, None));
1541 }
1542 }
1543 guar
1544 }
1545
1546 fn emit_diagnostic(
1548 &mut self,
1549 mut diagnostic: DiagInner,
1550 taint: Option<&Cell<Option<ErrorGuaranteed>>>,
1551 ) -> Option<ErrorGuaranteed> {
1552 if diagnostic.has_future_breakage() {
1553 assert_matches!(diagnostic.level, Error | ForceWarning | Warning | Allow | Expect);
1557 self.future_breakage_diagnostics.push(diagnostic.clone());
1558 }
1559
1560 match diagnostic.level {
1564 Bug => {}
1565 Fatal | Error => {
1566 if self.treat_next_err_as_bug() {
1567 diagnostic.level = Bug;
1569 }
1570 }
1571 DelayedBug => {
1572 if self.flags.eagerly_emit_delayed_bugs {
1577 if self.treat_next_err_as_bug() {
1579 diagnostic.level = Bug;
1580 } else {
1581 diagnostic.level = Error;
1582 }
1583 } else {
1584 return if let Some(guar) = self.has_errors() {
1587 Some(guar)
1588 } else {
1589 let backtrace = std::backtrace::Backtrace::capture();
1593 #[allow(deprecated)]
1597 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1598 self.delayed_bugs
1599 .push((DelayedDiagInner::with_backtrace(diagnostic, backtrace), guar));
1600 Some(guar)
1601 };
1602 }
1603 }
1604 ForceWarning if diagnostic.lint_id.is_none() => {} Warning => {
1606 if !self.flags.can_emit_warnings {
1607 if diagnostic.has_future_breakage() {
1609 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1611 }
1612 return None;
1613 }
1614 }
1615 Note | Help | FailureNote => {}
1616 OnceNote | OnceHelp => panic!("bad level: {:?}", diagnostic.level),
1617 Allow => {
1618 if diagnostic.has_future_breakage() {
1620 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1622 self.suppressed_expected_diag = true;
1623 }
1624 return None;
1625 }
1626 Expect | ForceWarning => {
1627 self.fulfilled_expectations.insert(diagnostic.lint_id.unwrap());
1628 if let Expect = diagnostic.level {
1629 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1631 self.suppressed_expected_diag = true;
1632 return None;
1633 }
1634 }
1635 }
1636
1637 TRACK_DIAGNOSTIC(diagnostic, &mut |mut diagnostic| {
1638 if let Some(code) = diagnostic.code {
1639 self.emitted_diagnostic_codes.insert(code);
1640 }
1641
1642 let already_emitted = {
1643 let mut hasher = StableHasher::new();
1644 diagnostic.hash(&mut hasher);
1645 let diagnostic_hash = hasher.finish();
1646 !self.emitted_diagnostics.insert(diagnostic_hash)
1647 };
1648
1649 let is_error = diagnostic.is_error();
1650 let is_lint = diagnostic.is_lint.is_some();
1651
1652 if !(self.flags.deduplicate_diagnostics && already_emitted) {
1655 debug!(?diagnostic);
1656 debug!(?self.emitted_diagnostics);
1657
1658 let not_yet_emitted = |sub: &mut Subdiag| {
1659 debug!(?sub);
1660 if sub.level != OnceNote && sub.level != OnceHelp {
1661 return true;
1662 }
1663 let mut hasher = StableHasher::new();
1664 sub.hash(&mut hasher);
1665 let diagnostic_hash = hasher.finish();
1666 debug!(?diagnostic_hash);
1667 self.emitted_diagnostics.insert(diagnostic_hash)
1668 };
1669 diagnostic.children.retain_mut(not_yet_emitted);
1670 if already_emitted {
1671 let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`";
1672 diagnostic.sub(Note, msg, MultiSpan::new());
1673 }
1674
1675 if is_error {
1676 self.deduplicated_err_count += 1;
1677 } else if matches!(diagnostic.level, ForceWarning | Warning) {
1678 self.deduplicated_warn_count += 1;
1679 }
1680 self.has_printed = true;
1681
1682 self.emitter.emit_diagnostic(diagnostic, &self.registry);
1683 }
1684
1685 if is_error {
1686 if !self.delayed_bugs.is_empty() {
1691 assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0);
1692 self.delayed_bugs.clear();
1693 self.delayed_bugs.shrink_to_fit();
1694 }
1695
1696 #[allow(deprecated)]
1699 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1700 if is_lint {
1701 self.lint_err_guars.push(guar);
1702 } else {
1703 if let Some(taint) = taint {
1704 taint.set(Some(guar));
1705 }
1706 self.err_guars.push(guar);
1707 }
1708 self.panic_if_treat_err_as_bug();
1709 Some(guar)
1710 } else {
1711 None
1712 }
1713 })
1714 }
1715
1716 fn treat_err_as_bug(&self) -> bool {
1717 self.flags
1718 .treat_err_as_bug
1719 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
1720 }
1721
1722 fn treat_next_err_as_bug(&self) -> bool {
1724 self.flags
1725 .treat_err_as_bug
1726 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
1727 }
1728
1729 fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1730 self.err_guars.get(0).copied().or_else(|| {
1731 if let Some((_diag, guar)) = self
1732 .stashed_diagnostics
1733 .values()
1734 .flat_map(|stashed_diagnostics| stashed_diagnostics.values())
1735 .find(|(diag, guar)| guar.is_some() && diag.is_lint.is_none())
1736 {
1737 *guar
1738 } else {
1739 None
1740 }
1741 })
1742 }
1743
1744 fn has_errors(&self) -> Option<ErrorGuaranteed> {
1745 self.err_guars.get(0).copied().or_else(|| self.lint_err_guars.get(0).copied()).or_else(
1746 || {
1747 self.stashed_diagnostics.values().find_map(|stashed_diagnostics| {
1748 stashed_diagnostics.values().find_map(|(_, guar)| *guar)
1749 })
1750 },
1751 )
1752 }
1753
1754 fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1755 self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
1756 }
1757
1758 fn eagerly_translate<'a>(
1760 &self,
1761 message: DiagMessage,
1762 args: impl Iterator<Item = DiagArg<'a>>,
1763 ) -> SubdiagMessage {
1764 SubdiagMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
1765 }
1766
1767 fn eagerly_translate_to_string<'a>(
1769 &self,
1770 message: DiagMessage,
1771 args: impl Iterator<Item = DiagArg<'a>>,
1772 ) -> String {
1773 let args = crate::translation::to_fluent_args(args);
1774 self.emitter.translate_message(&message, &args).map_err(Report::new).unwrap().to_string()
1775 }
1776
1777 fn eagerly_translate_for_subdiag(
1778 &self,
1779 diag: &DiagInner,
1780 msg: impl Into<SubdiagMessage>,
1781 ) -> SubdiagMessage {
1782 let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
1783 self.eagerly_translate(msg, diag.args.iter())
1784 }
1785
1786 fn flush_delayed(&mut self) {
1787 assert!(self.stashed_diagnostics.is_empty());
1791
1792 if !self.err_guars.is_empty() {
1793 return;
1795 }
1796
1797 if self.delayed_bugs.is_empty() {
1798 return;
1800 }
1801
1802 let bugs: Vec<_> =
1803 std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
1804
1805 let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0"));
1806 let decorate = backtrace || self.ice_file.is_none();
1807 let mut out = self
1808 .ice_file
1809 .as_ref()
1810 .and_then(|file| std::fs::File::options().create(true).append(true).open(file).ok());
1811
1812 let note1 = "no errors encountered even though delayed bugs were created";
1817 let note2 = "those delayed bugs will now be shown as internal compiler errors";
1818 self.emit_diagnostic(DiagInner::new(Note, note1), None);
1819 self.emit_diagnostic(DiagInner::new(Note, note2), None);
1820
1821 for bug in bugs {
1822 if let Some(out) = &mut out {
1823 _ = write!(
1824 out,
1825 "delayed bug: {}\n{}\n",
1826 bug.inner
1827 .messages
1828 .iter()
1829 .filter_map(|(msg, _)| msg.as_str())
1830 .collect::<String>(),
1831 &bug.note
1832 );
1833 }
1834
1835 let mut bug = if decorate { bug.decorate(self) } else { bug.inner };
1836
1837 if bug.level != DelayedBug {
1839 bug.arg("level", bug.level);
1846 let msg = crate::fluent_generated::errors_invalid_flushed_delayed_diagnostic_level;
1847 let msg = self.eagerly_translate_for_subdiag(&bug, msg); bug.sub(Note, msg, bug.span.primary_span().unwrap().into());
1849 }
1850 bug.level = Bug;
1851
1852 self.emit_diagnostic(bug, None);
1853 }
1854
1855 panic::panic_any(DelayedBugPanic);
1857 }
1858
1859 fn panic_if_treat_err_as_bug(&self) {
1860 if self.treat_err_as_bug() {
1861 let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
1862 assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
1863 if n == 1 {
1864 panic!("aborting due to `-Z treat-err-as-bug=1`");
1865 } else {
1866 panic!("aborting after {n} errors due to `-Z treat-err-as-bug={n}`");
1867 }
1868 }
1869 }
1870}
1871
1872struct DelayedDiagInner {
1873 inner: DiagInner,
1874 note: Backtrace,
1875}
1876
1877impl DelayedDiagInner {
1878 fn with_backtrace(diagnostic: DiagInner, backtrace: Backtrace) -> Self {
1879 DelayedDiagInner { inner: diagnostic, note: backtrace }
1880 }
1881
1882 fn decorate(self, dcx: &DiagCtxtInner) -> DiagInner {
1883 let mut diag = self.inner;
1887 let msg = match self.note.status() {
1888 BacktraceStatus::Captured => crate::fluent_generated::errors_delayed_at_with_newline,
1889 _ => crate::fluent_generated::errors_delayed_at_without_newline,
1892 };
1893 diag.arg("emitted_at", diag.emitted_at.clone());
1894 diag.arg("note", self.note);
1895 let msg = dcx.eagerly_translate_for_subdiag(&diag, msg); diag.sub(Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into());
1897 diag
1898 }
1899}
1900
1901#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
1921pub enum Level {
1922 Bug,
1924
1925 Fatal,
1928
1929 Error,
1932
1933 DelayedBug,
1938
1939 ForceWarning,
1945
1946 Warning,
1949
1950 Note,
1952
1953 OnceNote,
1955
1956 Help,
1958
1959 OnceHelp,
1961
1962 FailureNote,
1965
1966 Allow,
1968
1969 Expect,
1971}
1972
1973impl fmt::Display for Level {
1974 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1975 self.to_str().fmt(f)
1976 }
1977}
1978
1979impl Level {
1980 fn color(self) -> ColorSpec {
1981 let mut spec = ColorSpec::new();
1982 match self {
1983 Bug | Fatal | Error | DelayedBug => {
1984 spec.set_fg(Some(Color::Red)).set_intense(true);
1985 }
1986 ForceWarning | Warning => {
1987 spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
1988 }
1989 Note | OnceNote => {
1990 spec.set_fg(Some(Color::Green)).set_intense(true);
1991 }
1992 Help | OnceHelp => {
1993 spec.set_fg(Some(Color::Cyan)).set_intense(true);
1994 }
1995 FailureNote => {}
1996 Allow | Expect => unreachable!(),
1997 }
1998 spec
1999 }
2000
2001 pub fn to_str(self) -> &'static str {
2002 match self {
2003 Bug | DelayedBug => "error: internal compiler error",
2004 Fatal | Error => "error",
2005 ForceWarning | Warning => "warning",
2006 Note | OnceNote => "note",
2007 Help | OnceHelp => "help",
2008 FailureNote => "failure-note",
2009 Allow | Expect => unreachable!(),
2010 }
2011 }
2012
2013 pub fn is_failure_note(&self) -> bool {
2014 matches!(*self, FailureNote)
2015 }
2016
2017 fn can_be_subdiag(&self) -> bool {
2019 match self {
2020 Bug | DelayedBug | Fatal | Error | ForceWarning | FailureNote | Allow | Expect => false,
2021
2022 Warning | Note | Help | OnceNote | OnceHelp => true,
2023 }
2024 }
2025}
2026
2027pub fn elided_lifetime_in_path_suggestion(
2029 source_map: &SourceMap,
2030 n: usize,
2031 path_span: Span,
2032 incl_angl_brckt: bool,
2033 insertion_span: Span,
2034) -> ElidedLifetimeInPathSubdiag {
2035 let expected = ExpectedLifetimeParameter { span: path_span, count: n };
2036 let indicate = source_map.is_span_accessible(insertion_span).then(|| {
2038 let anon_lts = vec!["'_"; n].join(", ");
2039 let suggestion =
2040 if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
2041
2042 IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
2043 });
2044
2045 ElidedLifetimeInPathSubdiag { expected, indicate }
2046}
2047
2048pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
2049 diag: &mut Diag<'a, G>,
2050 ambiguity: rustc_lint_defs::AmbiguityErrorDiag,
2051) {
2052 diag.span_label(ambiguity.label_span, ambiguity.label_msg);
2053 diag.note(ambiguity.note_msg);
2054 diag.span_note(ambiguity.b1_span, ambiguity.b1_note_msg);
2055 for help_msg in ambiguity.b1_help_msgs {
2056 diag.help(help_msg);
2057 }
2058 diag.span_note(ambiguity.b2_span, ambiguity.b2_note_msg);
2059 for help_msg in ambiguity.b2_help_msgs {
2060 diag.help(help_msg);
2061 }
2062}
2063
2064pub fn a_or_an(s: &str) -> &'static str {
2068 let mut chars = s.chars();
2069 let Some(mut first_alpha_char) = chars.next() else {
2070 return "a";
2071 };
2072 if first_alpha_char == '`' {
2073 let Some(next) = chars.next() else {
2074 return "a";
2075 };
2076 first_alpha_char = next;
2077 }
2078 if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
2079 "an"
2080 } else {
2081 "a"
2082 }
2083}
2084
2085#[derive(Clone, Copy, PartialEq, Hash, Debug)]
2086pub enum TerminalUrl {
2087 No,
2088 Yes,
2089 Auto,
2090}