1#![allow(internal_features)]
7#![allow(rustc::diagnostic_outside_of_impl)]
8#![allow(rustc::direct_use_of_rustc_type_ir)]
9#![allow(rustc::untranslatable_diagnostic)]
10#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
11#![doc(rust_logo)]
12#![feature(array_windows)]
13#![feature(assert_matches)]
14#![feature(associated_type_defaults)]
15#![feature(box_patterns)]
16#![feature(default_field_values)]
17#![feature(error_reporter)]
18#![feature(negative_impls)]
19#![feature(never_type)]
20#![feature(rustc_attrs)]
21#![feature(rustdoc_internals)]
22#![feature(try_blocks)]
23#![feature(yeet_expr)]
24extern crate self as rustc_errors;
27
28use std::assert_matches::assert_matches;
29use std::backtrace::{Backtrace, BacktraceStatus};
30use std::borrow::Cow;
31use std::cell::Cell;
32use std::error::Report;
33use std::ffi::OsStr;
34use std::hash::Hash;
35use std::io::Write;
36use std::num::NonZero;
37use std::ops::DerefMut;
38use std::path::{Path, PathBuf};
39use std::{fmt, panic};
40
41use Level::*;
42pub use codes::*;
43pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
44pub use diagnostic::{
45 BugAbort, Diag, DiagArgMap, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee,
46 FatalAbort, LintDiagnostic, LintDiagnosticBox, StringPart, Subdiag, Subdiagnostic,
47};
48pub use diagnostic_impls::{
49 DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
50 IndicateAnonymousLifetime, SingleLabelManySpans,
51};
52pub use emitter::ColorConfig;
53use emitter::{ConfusionType, DynEmitter, Emitter, detect_confusion_type, is_different};
54use rustc_data_structures::AtomicRef;
55use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
56use rustc_data_structures::stable_hasher::StableHasher;
57use rustc_data_structures::sync::{DynSend, Lock};
58pub use rustc_error_messages::{
59 DiagArg, DiagArgFromDisplay, DiagArgName, DiagArgValue, DiagMessage, FluentBundle, IntoDiagArg,
60 LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage,
61 fallback_fluent_bundle, fluent_bundle, into_diag_arg_using_display,
62};
63use rustc_hashes::Hash128;
64pub use rustc_lint_defs::{Applicability, listify, pluralize};
65use rustc_lint_defs::{Lint, LintExpectationId};
66use rustc_macros::{Decodable, Encodable};
67pub use rustc_span::ErrorGuaranteed;
68pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
69use rustc_span::source_map::SourceMap;
70use rustc_span::{BytePos, DUMMY_SP, Loc, Span};
71pub use snippet::Style;
72pub use termcolor::{Color, ColorSpec, WriteColor};
75use tracing::debug;
76
77use crate::emitter::TimingEvent;
78use crate::registry::Registry;
79use crate::timings::TimingRecord;
80
81pub mod annotate_snippet_emitter_writer;
82pub mod codes;
83mod decorate_diag;
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 type Id: Copy;
113 #[track_caller]
114 fn emit_node_span_lint(
115 self,
116 lint: &'static Lint,
117 hir_id: Self::Id,
118 span: impl Into<MultiSpan>,
119 decorator: impl for<'a> LintDiagnostic<'a, ()> + DynSend + 'static,
120 );
121}
122
123#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
124pub enum SuggestionStyle {
125 HideCodeInline,
127 HideCodeAlways,
129 CompletelyHidden,
131 ShowCode,
135 ShowAlways,
137}
138
139impl SuggestionStyle {
140 fn hide_inline(&self) -> bool {
141 !matches!(*self, SuggestionStyle::ShowCode)
142 }
143}
144
145#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
147pub enum Suggestions {
148 Enabled(Vec<CodeSuggestion>),
153 Sealed(Box<[CodeSuggestion]>),
157 Disabled,
161}
162
163impl Suggestions {
164 pub fn unwrap_tag(self) -> Vec<CodeSuggestion> {
166 match self {
167 Suggestions::Enabled(suggestions) => suggestions,
168 Suggestions::Sealed(suggestions) => suggestions.into_vec(),
169 Suggestions::Disabled => Vec::new(),
170 }
171 }
172}
173
174impl Default for Suggestions {
175 fn default() -> Self {
176 Self::Enabled(vec![])
177 }
178}
179
180#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
181pub struct CodeSuggestion {
182 pub substitutions: Vec<Substitution>,
204 pub msg: DiagMessage,
205 pub style: SuggestionStyle,
207 pub applicability: Applicability,
213}
214
215#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
216pub struct Substitution {
218 pub parts: Vec<SubstitutionPart>,
219}
220
221#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
222pub struct SubstitutionPart {
223 pub span: Span,
224 pub snippet: String,
225}
226
227#[derive(Debug, Clone, Copy)]
230pub(crate) struct SubstitutionHighlight {
231 start: usize,
232 end: usize,
233}
234
235impl SubstitutionPart {
236 pub fn is_addition(&self, sm: &SourceMap) -> bool {
237 !self.snippet.is_empty() && !self.replaces_meaningful_content(sm)
238 }
239
240 pub fn is_deletion(&self, sm: &SourceMap) -> bool {
241 self.snippet.trim().is_empty() && self.replaces_meaningful_content(sm)
242 }
243
244 pub fn is_replacement(&self, sm: &SourceMap) -> bool {
245 !self.snippet.is_empty() && self.replaces_meaningful_content(sm)
246 }
247
248 pub fn is_destructive_replacement(&self, sm: &SourceMap) -> bool {
253 self.is_replacement(sm)
254 && !sm
255 .span_to_snippet(self.span)
256 .is_ok_and(|snippet| as_substr(snippet.trim(), self.snippet.trim()).is_some())
257 }
258
259 fn replaces_meaningful_content(&self, sm: &SourceMap) -> bool {
260 sm.span_to_snippet(self.span)
261 .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty())
262 }
263
264 fn trim_trivial_replacements(&mut self, sm: &SourceMap) {
267 if self.snippet.is_empty() {
268 return;
269 }
270 let Ok(snippet) = sm.span_to_snippet(self.span) else {
271 return;
272 };
273
274 if let Some((prefix, substr, suffix)) = as_substr(&snippet, &self.snippet) {
275 self.span = Span::new(
276 self.span.lo() + BytePos(prefix as u32),
277 self.span.hi() - BytePos(suffix as u32),
278 self.span.ctxt(),
279 self.span.parent(),
280 );
281 self.snippet = substr.to_string();
282 }
283 }
284}
285
286fn as_substr<'a>(original: &'a str, suggestion: &'a str) -> Option<(usize, &'a str, usize)> {
291 let common_prefix = original
292 .chars()
293 .zip(suggestion.chars())
294 .take_while(|(c1, c2)| c1 == c2)
295 .map(|(c, _)| c.len_utf8())
296 .sum();
297 let original = &original[common_prefix..];
298 let suggestion = &suggestion[common_prefix..];
299 if suggestion.ends_with(original) {
300 let common_suffix = original.len();
301 Some((common_prefix, &suggestion[..suggestion.len() - original.len()], common_suffix))
302 } else {
303 None
304 }
305}
306
307impl CodeSuggestion {
308 pub(crate) fn splice_lines(
311 &self,
312 sm: &SourceMap,
313 ) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, ConfusionType)> {
314 use rustc_span::{CharPos, Pos};
319
320 fn push_trailing(
329 buf: &mut String,
330 line_opt: Option<&Cow<'_, str>>,
331 lo: &Loc,
332 hi_opt: Option<&Loc>,
333 ) -> usize {
334 let mut line_count = 0;
335 let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
338 if let Some(line) = line_opt {
339 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
340 let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
342 match hi_opt {
343 Some(hi) if hi > lo => {
345 line_count = line[lo..hi].matches('\n').count();
347 buf.push_str(&line[lo..hi])
348 }
349 Some(_) => (),
350 None => {
352 line_count = line[lo..].matches('\n').count();
354 buf.push_str(&line[lo..])
355 }
356 }
357 }
358 if hi_opt.is_none() {
360 buf.push('\n');
361 }
362 }
363 line_count
364 }
365
366 assert!(!self.substitutions.is_empty());
367
368 self.substitutions
369 .iter()
370 .filter(|subst| {
371 let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
374 if invalid {
375 debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
376 }
377 !invalid
378 })
379 .cloned()
380 .filter_map(|mut substitution| {
381 substitution.parts.sort_by_key(|part| part.span.lo());
384
385 let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
387 let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
388 let bounding_span = Span::with_root_ctxt(lo, hi);
389 let lines = sm.span_to_lines(bounding_span).ok()?;
391 assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
392
393 if !sm.ensure_source_file_source_present(&lines.file) {
395 return None;
396 }
397
398 let mut highlights = vec![];
399 let sf = &lines.file;
409 let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
410 prev_hi.col = CharPos::from_usize(0);
411 let mut prev_line =
412 lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
413 let mut buf = String::new();
414
415 let mut line_highlight = vec![];
416 let mut acc = 0;
419 let mut confusion_type = ConfusionType::None;
420 for part in &mut substitution.parts {
421 part.trim_trivial_replacements(sm);
425
426 let part_confusion = detect_confusion_type(sm, &part.snippet, part.span);
427 confusion_type = confusion_type.combine(part_confusion);
428 let cur_lo = sm.lookup_char_pos(part.span.lo());
429 if prev_hi.line == cur_lo.line {
430 let mut count =
431 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
432 while count > 0 {
433 highlights.push(std::mem::take(&mut line_highlight));
434 acc = 0;
435 count -= 1;
436 }
437 } else {
438 acc = 0;
439 highlights.push(std::mem::take(&mut line_highlight));
440 let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
441 while count > 0 {
442 highlights.push(std::mem::take(&mut line_highlight));
443 count -= 1;
444 }
445 for idx in prev_hi.line..(cur_lo.line - 1) {
447 if let Some(line) = sf.get_line(idx) {
448 buf.push_str(line.as_ref());
449 buf.push('\n');
450 highlights.push(std::mem::take(&mut line_highlight));
451 }
452 }
453 if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
454 let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
455 Some((i, _)) => i,
456 None => cur_line.len(),
457 };
458 buf.push_str(&cur_line[..end]);
459 }
460 }
461 let len: isize = part
463 .snippet
464 .split('\n')
465 .next()
466 .unwrap_or(&part.snippet)
467 .chars()
468 .map(|c| match c {
469 '\t' => 4,
470 _ => 1,
471 })
472 .sum();
473 if !is_different(sm, &part.snippet, part.span) {
474 } else {
478 line_highlight.push(SubstitutionHighlight {
479 start: (cur_lo.col.0 as isize + acc) as usize,
480 end: (cur_lo.col.0 as isize + acc + len) as usize,
481 });
482 }
483 buf.push_str(&part.snippet);
484 let cur_hi = sm.lookup_char_pos(part.span.hi());
485 acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
490 prev_hi = cur_hi;
491 prev_line = sf.get_line(prev_hi.line - 1);
492 for line in part.snippet.split('\n').skip(1) {
493 acc = 0;
494 highlights.push(std::mem::take(&mut line_highlight));
495 let end: usize = line
496 .chars()
497 .map(|c| match c {
498 '\t' => 4,
499 _ => 1,
500 })
501 .sum();
502 line_highlight.push(SubstitutionHighlight { start: 0, end });
503 }
504 }
505 highlights.push(std::mem::take(&mut line_highlight));
506 if !buf.ends_with('\n') {
508 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
509 }
510 while buf.ends_with('\n') {
512 buf.pop();
513 }
514 if highlights.iter().all(|parts| parts.is_empty()) {
515 None
516 } else {
517 Some((buf, substitution.parts, highlights, confusion_type))
518 }
519 })
520 .collect()
521 }
522}
523
524pub struct ExplicitBug;
527
528pub struct DelayedBugPanic;
531
532pub struct DiagCtxt {
536 inner: Lock<DiagCtxtInner>,
537}
538
539#[derive(Copy, Clone)]
540pub struct DiagCtxtHandle<'a> {
541 dcx: &'a DiagCtxt,
542 tainted_with_errors: Option<&'a Cell<Option<ErrorGuaranteed>>>,
545}
546
547impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
548 type Target = &'a DiagCtxt;
549
550 fn deref(&self) -> &Self::Target {
551 &self.dcx
552 }
553}
554
555struct DiagCtxtInner {
559 flags: DiagCtxtFlags,
560
561 registry: Registry,
562
563 err_guars: Vec<ErrorGuaranteed>,
565 lint_err_guars: Vec<ErrorGuaranteed>,
568 delayed_bugs: Vec<(DelayedDiagInner, ErrorGuaranteed)>,
570
571 deduplicated_err_count: usize,
573 deduplicated_warn_count: usize,
575
576 emitter: Box<DynEmitter>,
577
578 must_produce_diag: Option<Backtrace>,
581
582 has_printed: bool,
585
586 suppressed_expected_diag: bool,
589
590 taught_diagnostics: FxHashSet<ErrCode>,
594
595 emitted_diagnostic_codes: FxIndexSet<ErrCode>,
597
598 emitted_diagnostics: FxHashSet<Hash128>,
602
603 stashed_diagnostics:
609 FxIndexMap<StashKey, FxIndexMap<Span, (DiagInner, Option<ErrorGuaranteed>)>>,
610
611 future_breakage_diagnostics: Vec<DiagInner>,
612
613 fulfilled_expectations: FxIndexSet<LintExpectationId>,
625
626 ice_file: Option<PathBuf>,
629}
630
631#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
633pub enum StashKey {
634 ItemNoType,
635 UnderscoreForArrayLengths,
636 EarlySyntaxWarning,
637 CallIntoMethod,
638 LifetimeIsChar,
641 MaybeFruTypo,
644 CallAssocMethod,
645 AssociatedTypeSuggestion,
646 Cycle,
648 UndeterminedMacroResolution,
649 ExprInPat,
651 GenericInFieldExpr,
655}
656
657fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
658 (*f)(diag)
659}
660
661pub static TRACK_DIAGNOSTIC: AtomicRef<
664 fn(DiagInner, &mut dyn FnMut(DiagInner) -> Option<ErrorGuaranteed>) -> Option<ErrorGuaranteed>,
665> = AtomicRef::new(&(default_track_diagnostic as _));
666
667#[derive(Copy, Clone, Default)]
668pub struct DiagCtxtFlags {
669 pub can_emit_warnings: bool,
672 pub treat_err_as_bug: Option<NonZero<usize>>,
675 pub eagerly_emit_delayed_bugs: bool,
678 pub macro_backtrace: bool,
681 pub deduplicate_diagnostics: bool,
683 pub track_diagnostics: bool,
685}
686
687impl Drop for DiagCtxtInner {
688 fn drop(&mut self) {
689 self.emit_stashed_diagnostics();
697
698 self.flush_delayed();
702
703 if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
707 if let Some(backtrace) = &self.must_produce_diag {
708 let suggestion = match backtrace.status() {
709 BacktraceStatus::Disabled => String::from(
710 "Backtraces are currently disabled: set `RUST_BACKTRACE=1` and re-run \
711 to see where it happened.",
712 ),
713 BacktraceStatus::Captured => format!(
714 "This happened in the following `must_produce_diag` call's backtrace:\n\
715 {backtrace}",
716 ),
717 _ => String::from("(impossible to capture backtrace where this happened)"),
718 };
719 panic!(
720 "`trimmed_def_paths` called, diagnostics were expected but none were emitted. \
721 Use `with_no_trimmed_paths` for debugging. {suggestion}"
722 );
723 }
724 }
725 }
726}
727
728impl DiagCtxt {
729 pub fn disable_warnings(mut self) -> Self {
730 self.inner.get_mut().flags.can_emit_warnings = false;
731 self
732 }
733
734 pub fn with_flags(mut self, flags: DiagCtxtFlags) -> Self {
735 self.inner.get_mut().flags = flags;
736 self
737 }
738
739 pub fn with_ice_file(mut self, ice_file: PathBuf) -> Self {
740 self.inner.get_mut().ice_file = Some(ice_file);
741 self
742 }
743
744 pub fn with_registry(mut self, registry: Registry) -> Self {
745 self.inner.get_mut().registry = registry;
746 self
747 }
748
749 pub fn new(emitter: Box<DynEmitter>) -> Self {
750 Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
751 }
752
753 pub fn make_silent(&self) {
754 let mut inner = self.inner.borrow_mut();
755 let translator = inner.emitter.translator().clone();
756 inner.emitter = Box::new(emitter::SilentEmitter { translator });
757 }
758
759 pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) {
760 self.inner.borrow_mut().emitter = emitter;
761 }
762
763 pub fn eagerly_translate<'a>(
765 &self,
766 message: DiagMessage,
767 args: impl Iterator<Item = DiagArg<'a>>,
768 ) -> SubdiagMessage {
769 let inner = self.inner.borrow();
770 inner.eagerly_translate(message, args)
771 }
772
773 pub fn eagerly_translate_to_string<'a>(
775 &self,
776 message: DiagMessage,
777 args: impl Iterator<Item = DiagArg<'a>>,
778 ) -> String {
779 let inner = self.inner.borrow();
780 inner.eagerly_translate_to_string(message, args)
781 }
782
783 pub fn can_emit_warnings(&self) -> bool {
787 self.inner.borrow_mut().flags.can_emit_warnings
788 }
789
790 pub fn reset_err_count(&self) {
796 let mut inner = self.inner.borrow_mut();
799 let DiagCtxtInner {
800 flags: _,
801 registry: _,
802 err_guars,
803 lint_err_guars,
804 delayed_bugs,
805 deduplicated_err_count,
806 deduplicated_warn_count,
807 emitter: _,
808 must_produce_diag,
809 has_printed,
810 suppressed_expected_diag,
811 taught_diagnostics,
812 emitted_diagnostic_codes,
813 emitted_diagnostics,
814 stashed_diagnostics,
815 future_breakage_diagnostics,
816 fulfilled_expectations,
817 ice_file: _,
818 } = inner.deref_mut();
819
820 *err_guars = Default::default();
823 *lint_err_guars = Default::default();
824 *delayed_bugs = Default::default();
825 *deduplicated_err_count = 0;
826 *deduplicated_warn_count = 0;
827 *must_produce_diag = None;
828 *has_printed = false;
829 *suppressed_expected_diag = false;
830 *taught_diagnostics = Default::default();
831 *emitted_diagnostic_codes = Default::default();
832 *emitted_diagnostics = Default::default();
833 *stashed_diagnostics = Default::default();
834 *future_breakage_diagnostics = Default::default();
835 *fulfilled_expectations = Default::default();
836 }
837
838 pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> {
839 DiagCtxtHandle { dcx: self, tainted_with_errors: None }
840 }
841
842 pub fn taintable_handle<'a>(
846 &'a self,
847 tainted_with_errors: &'a Cell<Option<ErrorGuaranteed>>,
848 ) -> DiagCtxtHandle<'a> {
849 DiagCtxtHandle { dcx: self, tainted_with_errors: Some(tainted_with_errors) }
850 }
851}
852
853impl<'a> DiagCtxtHandle<'a> {
854 pub fn stash_diagnostic(
876 &self,
877 span: Span,
878 key: StashKey,
879 diag: DiagInner,
880 ) -> Option<ErrorGuaranteed> {
881 let guar = match diag.level {
882 Bug | Fatal => {
883 self.span_bug(
884 span,
885 format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
886 );
887 }
888 Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
892 DelayedBug => {
893 return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors);
894 }
895 ForceWarning | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
896 | Expect => None,
897 };
898
899 self.inner
903 .borrow_mut()
904 .stashed_diagnostics
905 .entry(key)
906 .or_default()
907 .insert(span.with_parent(None), (diag, guar));
908
909 guar
910 }
911
912 pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
916 let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
918 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
919 )?;
920 assert!(!diag.is_error());
921 assert!(guar.is_none());
922 Some(Diag::new_diagnostic(self, diag))
923 }
924
925 pub fn try_steal_modify_and_emit_err<F>(
930 self,
931 span: Span,
932 key: StashKey,
933 mut modify_err: F,
934 ) -> Option<ErrorGuaranteed>
935 where
936 F: FnMut(&mut Diag<'_>),
937 {
938 let err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
940 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
941 );
942 err.map(|(err, guar)| {
943 assert_eq!(err.level, Error);
945 assert!(guar.is_some());
946 let mut err = Diag::<ErrorGuaranteed>::new_diagnostic(self, err);
947 modify_err(&mut err);
948 assert_eq!(err.level, Error);
949 err.emit()
950 })
951 }
952
953 pub fn try_steal_replace_and_emit_err(
957 self,
958 span: Span,
959 key: StashKey,
960 new_err: Diag<'_>,
961 ) -> ErrorGuaranteed {
962 let old_err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
964 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
965 );
966 match old_err {
967 Some((old_err, guar)) => {
968 assert_eq!(old_err.level, Error);
969 assert!(guar.is_some());
970 Diag::<ErrorGuaranteed>::new_diagnostic(self, old_err).cancel();
973 }
974 None => {}
975 };
976 new_err.emit()
977 }
978
979 pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
980 let inner = self.inner.borrow();
981 if let Some(stashed_diagnostics) = inner.stashed_diagnostics.get(&key)
982 && !stashed_diagnostics.is_empty()
983 {
984 stashed_diagnostics.contains_key(&span.with_parent(None))
985 } else {
986 false
987 }
988 }
989
990 pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
992 self.inner.borrow_mut().emit_stashed_diagnostics()
993 }
994
995 #[inline]
997 pub fn err_count(&self) -> usize {
998 let inner = self.inner.borrow();
999 inner.err_guars.len()
1000 + inner.lint_err_guars.len()
1001 + inner
1002 .stashed_diagnostics
1003 .values()
1004 .map(|a| a.values().filter(|(_, guar)| guar.is_some()).count())
1005 .sum::<usize>()
1006 }
1007
1008 pub fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1011 self.inner.borrow().has_errors_excluding_lint_errors()
1012 }
1013
1014 pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
1016 self.inner.borrow().has_errors()
1017 }
1018
1019 pub fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1022 self.inner.borrow().has_errors_or_delayed_bugs()
1023 }
1024
1025 pub fn print_error_count(&self) {
1026 let mut inner = self.inner.borrow_mut();
1027
1028 assert!(inner.stashed_diagnostics.is_empty());
1031
1032 if inner.treat_err_as_bug() {
1033 return;
1034 }
1035
1036 let warnings = match inner.deduplicated_warn_count {
1037 0 => Cow::from(""),
1038 1 => Cow::from("1 warning emitted"),
1039 count => Cow::from(format!("{count} warnings emitted")),
1040 };
1041 let errors = match inner.deduplicated_err_count {
1042 0 => Cow::from(""),
1043 1 => Cow::from("aborting due to 1 previous error"),
1044 count => Cow::from(format!("aborting due to {count} previous errors")),
1045 };
1046
1047 match (errors.len(), warnings.len()) {
1048 (0, 0) => return,
1049 (0, _) => {
1050 inner.emit_diagnostic(
1053 DiagInner::new(ForceWarning, DiagMessage::Str(warnings)),
1054 None,
1055 );
1056 }
1057 (_, 0) => {
1058 inner.emit_diagnostic(DiagInner::new(Error, errors), self.tainted_with_errors);
1059 }
1060 (_, _) => {
1061 inner.emit_diagnostic(
1062 DiagInner::new(Error, format!("{errors}; {warnings}")),
1063 self.tainted_with_errors,
1064 );
1065 }
1066 }
1067
1068 let can_show_explain = inner.emitter.should_show_explain();
1069 let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty();
1070 if can_show_explain && are_there_diagnostics {
1071 let mut error_codes = inner
1072 .emitted_diagnostic_codes
1073 .iter()
1074 .filter_map(|&code| {
1075 if inner.registry.try_find_description(code).is_ok() {
1076 Some(code.to_string())
1077 } else {
1078 None
1079 }
1080 })
1081 .collect::<Vec<_>>();
1082 if !error_codes.is_empty() {
1083 error_codes.sort();
1084 if error_codes.len() > 1 {
1085 let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
1086 let msg1 = format!(
1087 "Some errors have detailed explanations: {}{}",
1088 error_codes[..limit].join(", "),
1089 if error_codes.len() > 9 { "..." } else { "." }
1090 );
1091 let msg2 = format!(
1092 "For more information about an error, try `rustc --explain {}`.",
1093 &error_codes[0]
1094 );
1095 inner.emit_diagnostic(DiagInner::new(FailureNote, msg1), None);
1096 inner.emit_diagnostic(DiagInner::new(FailureNote, msg2), None);
1097 } else {
1098 let msg = format!(
1099 "For more information about this error, try `rustc --explain {}`.",
1100 &error_codes[0]
1101 );
1102 inner.emit_diagnostic(DiagInner::new(FailureNote, msg), None);
1103 }
1104 }
1105 }
1106 }
1107
1108 pub fn abort_if_errors(&self) {
1113 if let Some(guar) = self.has_errors() {
1114 guar.raise_fatal();
1115 }
1116 }
1117
1118 pub fn must_teach(&self, code: ErrCode) -> bool {
1124 self.inner.borrow_mut().taught_diagnostics.insert(code)
1125 }
1126
1127 pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
1128 self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors)
1129 }
1130
1131 pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
1132 self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
1133 }
1134
1135 pub fn emit_timing_section_start(&self, record: TimingRecord) {
1136 self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::Start);
1137 }
1138
1139 pub fn emit_timing_section_end(&self, record: TimingRecord) {
1140 self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::End);
1141 }
1142
1143 pub fn emit_future_breakage_report(&self) {
1144 let inner = &mut *self.inner.borrow_mut();
1145 let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
1146 if !diags.is_empty() {
1147 inner.emitter.emit_future_breakage_report(diags, &inner.registry);
1148 }
1149 }
1150
1151 pub fn emit_unused_externs(
1152 &self,
1153 lint_level: rustc_lint_defs::Level,
1154 loud: bool,
1155 unused_externs: &[&str],
1156 ) {
1157 let mut inner = self.inner.borrow_mut();
1158
1159 if loud && lint_level.is_error() {
1170 #[allow(deprecated)]
1173 inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
1174 inner.panic_if_treat_err_as_bug();
1175 }
1176
1177 inner.emitter.emit_unused_externs(lint_level, unused_externs)
1178 }
1179
1180 #[must_use]
1183 pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
1184 std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
1185 }
1186
1187 pub fn flush_delayed(&self) {
1188 self.inner.borrow_mut().flush_delayed();
1189 }
1190
1191 #[track_caller]
1194 pub fn set_must_produce_diag(&self) {
1195 assert!(
1196 self.inner.borrow().must_produce_diag.is_none(),
1197 "should only need to collect a backtrace once"
1198 );
1199 self.inner.borrow_mut().must_produce_diag = Some(Backtrace::capture());
1200 }
1201}
1202
1203impl<'a> DiagCtxtHandle<'a> {
1208 #[track_caller]
1211 pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> {
1212 Diag::new(self, Bug, msg.into())
1213 }
1214
1215 #[track_caller]
1218 pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
1219 self.struct_bug(msg).emit()
1220 }
1221
1222 #[track_caller]
1225 pub fn struct_span_bug(
1226 self,
1227 span: impl Into<MultiSpan>,
1228 msg: impl Into<Cow<'static, str>>,
1229 ) -> Diag<'a, BugAbort> {
1230 self.struct_bug(msg).with_span(span)
1231 }
1232
1233 #[track_caller]
1236 pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
1237 self.struct_span_bug(span, msg.into()).emit()
1238 }
1239
1240 #[track_caller]
1241 pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> {
1242 bug.into_diag(self, Bug)
1243 }
1244
1245 #[track_caller]
1246 pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! {
1247 self.create_bug(bug).emit()
1248 }
1249
1250 #[rustc_lint_diagnostics]
1251 #[track_caller]
1252 pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> {
1253 Diag::new(self, Fatal, msg)
1254 }
1255
1256 #[rustc_lint_diagnostics]
1257 #[track_caller]
1258 pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
1259 self.struct_fatal(msg).emit()
1260 }
1261
1262 #[rustc_lint_diagnostics]
1263 #[track_caller]
1264 pub fn struct_span_fatal(
1265 self,
1266 span: impl Into<MultiSpan>,
1267 msg: impl Into<DiagMessage>,
1268 ) -> Diag<'a, FatalAbort> {
1269 self.struct_fatal(msg).with_span(span)
1270 }
1271
1272 #[rustc_lint_diagnostics]
1273 #[track_caller]
1274 pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
1275 self.struct_span_fatal(span, msg).emit()
1276 }
1277
1278 #[track_caller]
1279 pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> {
1280 fatal.into_diag(self, Fatal)
1281 }
1282
1283 #[track_caller]
1284 pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
1285 self.create_fatal(fatal).emit()
1286 }
1287
1288 #[track_caller]
1289 pub fn create_almost_fatal(
1290 self,
1291 fatal: impl Diagnostic<'a, FatalError>,
1292 ) -> Diag<'a, FatalError> {
1293 fatal.into_diag(self, Fatal)
1294 }
1295
1296 #[track_caller]
1297 pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError {
1298 self.create_almost_fatal(fatal).emit()
1299 }
1300
1301 #[rustc_lint_diagnostics]
1303 #[track_caller]
1304 pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> {
1305 Diag::new(self, Error, msg)
1306 }
1307
1308 #[rustc_lint_diagnostics]
1309 #[track_caller]
1310 pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
1311 self.struct_err(msg).emit()
1312 }
1313
1314 #[rustc_lint_diagnostics]
1315 #[track_caller]
1316 pub fn struct_span_err(
1317 self,
1318 span: impl Into<MultiSpan>,
1319 msg: impl Into<DiagMessage>,
1320 ) -> Diag<'a> {
1321 self.struct_err(msg).with_span(span)
1322 }
1323
1324 #[rustc_lint_diagnostics]
1325 #[track_caller]
1326 pub fn span_err(
1327 self,
1328 span: impl Into<MultiSpan>,
1329 msg: impl Into<DiagMessage>,
1330 ) -> ErrorGuaranteed {
1331 self.struct_span_err(span, msg).emit()
1332 }
1333
1334 #[track_caller]
1335 pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> {
1336 err.into_diag(self, Error)
1337 }
1338
1339 #[track_caller]
1340 pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
1341 self.create_err(err).emit()
1342 }
1343
1344 #[track_caller]
1349 pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
1350 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
1351 }
1352
1353 #[track_caller]
1361 pub fn span_delayed_bug(
1362 self,
1363 sp: impl Into<MultiSpan>,
1364 msg: impl Into<Cow<'static, str>>,
1365 ) -> ErrorGuaranteed {
1366 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
1367 }
1368
1369 #[rustc_lint_diagnostics]
1370 #[track_caller]
1371 pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1372 Diag::new(self, Warning, msg)
1373 }
1374
1375 #[rustc_lint_diagnostics]
1376 #[track_caller]
1377 pub fn warn(self, msg: impl Into<DiagMessage>) {
1378 self.struct_warn(msg).emit()
1379 }
1380
1381 #[rustc_lint_diagnostics]
1382 #[track_caller]
1383 pub fn struct_span_warn(
1384 self,
1385 span: impl Into<MultiSpan>,
1386 msg: impl Into<DiagMessage>,
1387 ) -> Diag<'a, ()> {
1388 self.struct_warn(msg).with_span(span)
1389 }
1390
1391 #[rustc_lint_diagnostics]
1392 #[track_caller]
1393 pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1394 self.struct_span_warn(span, msg).emit()
1395 }
1396
1397 #[track_caller]
1398 pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1399 warning.into_diag(self, Warning)
1400 }
1401
1402 #[track_caller]
1403 pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) {
1404 self.create_warn(warning).emit()
1405 }
1406
1407 #[rustc_lint_diagnostics]
1408 #[track_caller]
1409 pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1410 Diag::new(self, Note, msg)
1411 }
1412
1413 #[rustc_lint_diagnostics]
1414 #[track_caller]
1415 pub fn note(&self, msg: impl Into<DiagMessage>) {
1416 self.struct_note(msg).emit()
1417 }
1418
1419 #[rustc_lint_diagnostics]
1420 #[track_caller]
1421 pub fn struct_span_note(
1422 self,
1423 span: impl Into<MultiSpan>,
1424 msg: impl Into<DiagMessage>,
1425 ) -> Diag<'a, ()> {
1426 self.struct_note(msg).with_span(span)
1427 }
1428
1429 #[rustc_lint_diagnostics]
1430 #[track_caller]
1431 pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1432 self.struct_span_note(span, msg).emit()
1433 }
1434
1435 #[track_caller]
1436 pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1437 note.into_diag(self, Note)
1438 }
1439
1440 #[track_caller]
1441 pub fn emit_note(self, note: impl Diagnostic<'a, ()>) {
1442 self.create_note(note).emit()
1443 }
1444
1445 #[rustc_lint_diagnostics]
1446 #[track_caller]
1447 pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1448 Diag::new(self, Help, msg)
1449 }
1450
1451 #[rustc_lint_diagnostics]
1452 #[track_caller]
1453 pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1454 Diag::new(self, FailureNote, msg)
1455 }
1456
1457 #[rustc_lint_diagnostics]
1458 #[track_caller]
1459 pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1460 Diag::new(self, Allow, msg)
1461 }
1462
1463 #[rustc_lint_diagnostics]
1464 #[track_caller]
1465 pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> {
1466 Diag::new(self, Expect, msg).with_lint_id(id)
1467 }
1468}
1469
1470impl DiagCtxtInner {
1475 fn new(emitter: Box<DynEmitter>) -> Self {
1476 Self {
1477 flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
1478 registry: Registry::new(&[]),
1479 err_guars: Vec::new(),
1480 lint_err_guars: Vec::new(),
1481 delayed_bugs: Vec::new(),
1482 deduplicated_err_count: 0,
1483 deduplicated_warn_count: 0,
1484 emitter,
1485 must_produce_diag: None,
1486 has_printed: false,
1487 suppressed_expected_diag: false,
1488 taught_diagnostics: Default::default(),
1489 emitted_diagnostic_codes: Default::default(),
1490 emitted_diagnostics: Default::default(),
1491 stashed_diagnostics: Default::default(),
1492 future_breakage_diagnostics: Vec::new(),
1493 fulfilled_expectations: Default::default(),
1494 ice_file: None,
1495 }
1496 }
1497
1498 fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
1500 let mut guar = None;
1501 let has_errors = !self.err_guars.is_empty();
1502 for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
1503 for (_, (diag, _guar)) in stashed_diagnostics {
1504 if !diag.is_error() {
1505 if !diag.is_force_warn() && has_errors {
1509 continue;
1510 }
1511 }
1512 guar = guar.or(self.emit_diagnostic(diag, None));
1513 }
1514 }
1515 guar
1516 }
1517
1518 fn emit_diagnostic(
1520 &mut self,
1521 mut diagnostic: DiagInner,
1522 taint: Option<&Cell<Option<ErrorGuaranteed>>>,
1523 ) -> Option<ErrorGuaranteed> {
1524 if diagnostic.has_future_breakage() {
1525 assert_matches!(diagnostic.level, Error | ForceWarning | Warning | Allow | Expect);
1529 self.future_breakage_diagnostics.push(diagnostic.clone());
1530 }
1531
1532 match diagnostic.level {
1536 Bug => {}
1537 Fatal | Error => {
1538 if self.treat_next_err_as_bug() {
1539 diagnostic.level = Bug;
1541 }
1542 }
1543 DelayedBug => {
1544 if self.flags.eagerly_emit_delayed_bugs {
1549 if self.treat_next_err_as_bug() {
1551 diagnostic.level = Bug;
1552 } else {
1553 diagnostic.level = Error;
1554 }
1555 } else {
1556 return if let Some(guar) = self.has_errors() {
1559 Some(guar)
1560 } else {
1561 let backtrace = std::backtrace::Backtrace::capture();
1565 #[allow(deprecated)]
1569 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1570 self.delayed_bugs
1571 .push((DelayedDiagInner::with_backtrace(diagnostic, backtrace), guar));
1572 Some(guar)
1573 };
1574 }
1575 }
1576 ForceWarning if diagnostic.lint_id.is_none() => {} Warning => {
1578 if !self.flags.can_emit_warnings {
1579 if diagnostic.has_future_breakage() {
1581 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1583 }
1584 return None;
1585 }
1586 }
1587 Note | Help | FailureNote => {}
1588 OnceNote | OnceHelp => panic!("bad level: {:?}", diagnostic.level),
1589 Allow => {
1590 if diagnostic.has_future_breakage() {
1592 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1594 self.suppressed_expected_diag = true;
1595 }
1596 return None;
1597 }
1598 Expect | ForceWarning => {
1599 self.fulfilled_expectations.insert(diagnostic.lint_id.unwrap());
1600 if let Expect = diagnostic.level {
1601 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1603 self.suppressed_expected_diag = true;
1604 return None;
1605 }
1606 }
1607 }
1608
1609 TRACK_DIAGNOSTIC(diagnostic, &mut |mut diagnostic| {
1610 if let Some(code) = diagnostic.code {
1611 self.emitted_diagnostic_codes.insert(code);
1612 }
1613
1614 let already_emitted = {
1615 let mut hasher = StableHasher::new();
1616 diagnostic.hash(&mut hasher);
1617 let diagnostic_hash = hasher.finish();
1618 !self.emitted_diagnostics.insert(diagnostic_hash)
1619 };
1620
1621 let is_error = diagnostic.is_error();
1622 let is_lint = diagnostic.is_lint.is_some();
1623
1624 if !(self.flags.deduplicate_diagnostics && already_emitted) {
1627 debug!(?diagnostic);
1628 debug!(?self.emitted_diagnostics);
1629
1630 let not_yet_emitted = |sub: &mut Subdiag| {
1631 debug!(?sub);
1632 if sub.level != OnceNote && sub.level != OnceHelp {
1633 return true;
1634 }
1635 let mut hasher = StableHasher::new();
1636 sub.hash(&mut hasher);
1637 let diagnostic_hash = hasher.finish();
1638 debug!(?diagnostic_hash);
1639 self.emitted_diagnostics.insert(diagnostic_hash)
1640 };
1641 diagnostic.children.retain_mut(not_yet_emitted);
1642 if already_emitted {
1643 let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`";
1644 diagnostic.sub(Note, msg, MultiSpan::new());
1645 }
1646
1647 if is_error {
1648 self.deduplicated_err_count += 1;
1649 } else if matches!(diagnostic.level, ForceWarning | Warning) {
1650 self.deduplicated_warn_count += 1;
1651 }
1652 self.has_printed = true;
1653
1654 self.emitter.emit_diagnostic(diagnostic, &self.registry);
1655 }
1656
1657 if is_error {
1658 if !self.delayed_bugs.is_empty() {
1663 assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0);
1664 self.delayed_bugs.clear();
1665 self.delayed_bugs.shrink_to_fit();
1666 }
1667
1668 #[allow(deprecated)]
1671 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1672 if is_lint {
1673 self.lint_err_guars.push(guar);
1674 } else {
1675 if let Some(taint) = taint {
1676 taint.set(Some(guar));
1677 }
1678 self.err_guars.push(guar);
1679 }
1680 self.panic_if_treat_err_as_bug();
1681 Some(guar)
1682 } else {
1683 None
1684 }
1685 })
1686 }
1687
1688 fn treat_err_as_bug(&self) -> bool {
1689 self.flags
1690 .treat_err_as_bug
1691 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
1692 }
1693
1694 fn treat_next_err_as_bug(&self) -> bool {
1696 self.flags
1697 .treat_err_as_bug
1698 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
1699 }
1700
1701 fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1702 self.err_guars.get(0).copied().or_else(|| {
1703 if let Some((_diag, guar)) = self
1704 .stashed_diagnostics
1705 .values()
1706 .flat_map(|stashed_diagnostics| stashed_diagnostics.values())
1707 .find(|(diag, guar)| guar.is_some() && diag.is_lint.is_none())
1708 {
1709 *guar
1710 } else {
1711 None
1712 }
1713 })
1714 }
1715
1716 fn has_errors(&self) -> Option<ErrorGuaranteed> {
1717 self.err_guars.get(0).copied().or_else(|| self.lint_err_guars.get(0).copied()).or_else(
1718 || {
1719 self.stashed_diagnostics.values().find_map(|stashed_diagnostics| {
1720 stashed_diagnostics.values().find_map(|(_, guar)| *guar)
1721 })
1722 },
1723 )
1724 }
1725
1726 fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1727 self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
1728 }
1729
1730 fn eagerly_translate<'a>(
1732 &self,
1733 message: DiagMessage,
1734 args: impl Iterator<Item = DiagArg<'a>>,
1735 ) -> SubdiagMessage {
1736 SubdiagMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
1737 }
1738
1739 fn eagerly_translate_to_string<'a>(
1741 &self,
1742 message: DiagMessage,
1743 args: impl Iterator<Item = DiagArg<'a>>,
1744 ) -> String {
1745 let args = crate::translation::to_fluent_args(args);
1746 self.emitter
1747 .translator()
1748 .translate_message(&message, &args)
1749 .map_err(Report::new)
1750 .unwrap()
1751 .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
2004impl IntoDiagArg for Level {
2005 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
2006 DiagArgValue::Str(Cow::from(self.to_string()))
2007 }
2008}
2009
2010pub fn elided_lifetime_in_path_suggestion(
2012 source_map: &SourceMap,
2013 n: usize,
2014 path_span: Span,
2015 incl_angl_brckt: bool,
2016 insertion_span: Span,
2017) -> ElidedLifetimeInPathSubdiag {
2018 let expected = ExpectedLifetimeParameter { span: path_span, count: n };
2019 let indicate = source_map.is_span_accessible(insertion_span).then(|| {
2021 let anon_lts = vec!["'_"; n].join(", ");
2022 let suggestion =
2023 if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
2024
2025 IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
2026 });
2027
2028 ElidedLifetimeInPathSubdiag { expected, indicate }
2029}
2030
2031pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
2032 diag: &mut Diag<'a, G>,
2033 ambiguity: rustc_lint_defs::AmbiguityErrorDiag,
2034) {
2035 diag.span_label(ambiguity.label_span, ambiguity.label_msg);
2036 diag.note(ambiguity.note_msg);
2037 diag.span_note(ambiguity.b1_span, ambiguity.b1_note_msg);
2038 for help_msg in ambiguity.b1_help_msgs {
2039 diag.help(help_msg);
2040 }
2041 diag.span_note(ambiguity.b2_span, ambiguity.b2_note_msg);
2042 for help_msg in ambiguity.b2_help_msgs {
2043 diag.help(help_msg);
2044 }
2045}
2046
2047pub fn a_or_an(s: &str) -> &'static str {
2051 let mut chars = s.chars();
2052 let Some(mut first_alpha_char) = chars.next() else {
2053 return "a";
2054 };
2055 if first_alpha_char == '`' {
2056 let Some(next) = chars.next() else {
2057 return "a";
2058 };
2059 first_alpha_char = next;
2060 }
2061 if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
2062 "an"
2063 } else {
2064 "a"
2065 }
2066}
2067
2068#[derive(Clone, Copy, PartialEq, Hash, Debug)]
2069pub enum TerminalUrl {
2070 No,
2071 Yes,
2072 Auto,
2073}