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