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#![feature(array_windows)]
11#![feature(assert_matches)]
12#![feature(associated_type_defaults)]
13#![feature(box_patterns)]
14#![feature(default_field_values)]
15#![feature(error_reporter)]
16#![feature(negative_impls)]
17#![feature(never_type)]
18#![feature(rustc_attrs)]
19#![feature(try_blocks)]
20#![feature(yeet_expr)]
21extern crate self as rustc_errors;
24
25use std::assert_matches::assert_matches;
26use std::backtrace::{Backtrace, BacktraceStatus};
27use std::borrow::Cow;
28use std::cell::Cell;
29use std::error::Report;
30use std::ffi::OsStr;
31use std::hash::Hash;
32use std::io::Write;
33use std::num::NonZero;
34use std::ops::DerefMut;
35use std::path::{Path, PathBuf};
36use std::{fmt, panic};
37
38use Level::*;
39pub use anstream::{AutoStream, ColorChoice};
42pub use anstyle::{
43 Ansi256Color, AnsiColor, Color, EffectIter, Effects, Reset, RgbColor, Style as Anstyle,
44};
45pub use codes::*;
46pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
47pub use diagnostic::{
48 BugAbort, Diag, DiagArgMap, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee,
49 FatalAbort, LintDiagnostic, LintDiagnosticBox, StringPart, Subdiag, Subdiagnostic,
50};
51pub use diagnostic_impls::{
52 DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
53 IndicateAnonymousLifetime, SingleLabelManySpans,
54};
55pub use emitter::ColorConfig;
56use emitter::{ConfusionType, DynEmitter, Emitter, detect_confusion_type, 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 DiagArg, DiagArgFromDisplay, DiagArgName, DiagArgValue, DiagMessage, FluentBundle, IntoDiagArg,
63 LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage,
64 fallback_fluent_bundle, fluent_bundle, into_diag_arg_using_display,
65};
66use rustc_hashes::Hash128;
67pub use rustc_lint_defs::{Applicability, listify, pluralize};
68use rustc_lint_defs::{Lint, LintExpectationId};
69use rustc_macros::{Decodable, Encodable};
70pub use rustc_span::ErrorGuaranteed;
71pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
72use rustc_span::source_map::SourceMap;
73use rustc_span::{BytePos, DUMMY_SP, Loc, Span};
74pub use snippet::Style;
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(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
228pub struct TrimmedSubstitutionPart {
229 pub original_span: Span,
230 pub span: Span,
231 pub snippet: String,
232}
233
234#[derive(Debug, Clone, Copy)]
237pub(crate) struct SubstitutionHighlight {
238 start: usize,
239 end: usize,
240}
241
242impl SubstitutionPart {
243 fn trim_trivial_replacements(self, sm: &SourceMap) -> TrimmedSubstitutionPart {
246 let mut trimmed_part = TrimmedSubstitutionPart {
247 original_span: self.span,
248 span: self.span,
249 snippet: self.snippet,
250 };
251 if trimmed_part.snippet.is_empty() {
252 return trimmed_part;
253 }
254 let Ok(snippet) = sm.span_to_snippet(trimmed_part.span) else {
255 return trimmed_part;
256 };
257
258 if let Some((prefix, substr, suffix)) = as_substr(&snippet, &trimmed_part.snippet) {
259 trimmed_part.span = Span::new(
260 trimmed_part.span.lo() + BytePos(prefix as u32),
261 trimmed_part.span.hi() - BytePos(suffix as u32),
262 trimmed_part.span.ctxt(),
263 trimmed_part.span.parent(),
264 );
265 trimmed_part.snippet = substr.to_string();
266 }
267 trimmed_part
268 }
269}
270
271impl TrimmedSubstitutionPart {
272 pub fn is_addition(&self, sm: &SourceMap) -> bool {
273 !self.snippet.is_empty() && !self.replaces_meaningful_content(sm)
274 }
275
276 pub fn is_deletion(&self, sm: &SourceMap) -> bool {
277 self.snippet.trim().is_empty() && self.replaces_meaningful_content(sm)
278 }
279
280 pub fn is_replacement(&self, sm: &SourceMap) -> bool {
281 !self.snippet.is_empty() && self.replaces_meaningful_content(sm)
282 }
283
284 pub fn is_destructive_replacement(&self, sm: &SourceMap) -> bool {
289 self.is_replacement(sm)
290 && !sm
291 .span_to_snippet(self.span)
292 .is_ok_and(|snippet| as_substr(snippet.trim(), self.snippet.trim()).is_some())
293 }
294
295 fn replaces_meaningful_content(&self, sm: &SourceMap) -> bool {
296 sm.span_to_snippet(self.span)
297 .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty())
298 }
299}
300
301fn as_substr<'a>(original: &'a str, suggestion: &'a str) -> Option<(usize, &'a str, usize)> {
306 let common_prefix = original
307 .chars()
308 .zip(suggestion.chars())
309 .take_while(|(c1, c2)| c1 == c2)
310 .map(|(c, _)| c.len_utf8())
311 .sum();
312 let original = &original[common_prefix..];
313 let suggestion = &suggestion[common_prefix..];
314 if suggestion.ends_with(original) {
315 let common_suffix = original.len();
316 Some((common_prefix, &suggestion[..suggestion.len() - original.len()], common_suffix))
317 } else {
318 None
319 }
320}
321
322impl CodeSuggestion {
323 pub(crate) fn splice_lines(
326 &self,
327 sm: &SourceMap,
328 ) -> Vec<(String, Vec<TrimmedSubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, ConfusionType)>
329 {
330 use rustc_span::{CharPos, Pos};
335
336 fn push_trailing(
345 buf: &mut String,
346 line_opt: Option<&Cow<'_, str>>,
347 lo: &Loc,
348 hi_opt: Option<&Loc>,
349 ) -> usize {
350 let mut line_count = 0;
351 let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
354 if let Some(line) = line_opt {
355 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
356 let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
358 match hi_opt {
359 Some(hi) if hi > lo => {
361 line_count = line[lo..hi].matches('\n').count();
363 buf.push_str(&line[lo..hi])
364 }
365 Some(_) => (),
366 None => {
368 line_count = line[lo..].matches('\n').count();
370 buf.push_str(&line[lo..])
371 }
372 }
373 }
374 if hi_opt.is_none() {
376 buf.push('\n');
377 }
378 }
379 line_count
380 }
381
382 assert!(!self.substitutions.is_empty());
383
384 self.substitutions
385 .iter()
386 .filter(|subst| {
387 let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
390 if invalid {
391 debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
392 }
393 !invalid
394 })
395 .cloned()
396 .filter_map(|mut substitution| {
397 substitution.parts.sort_by_key(|part| part.span.lo());
400
401 let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
403 let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
404 let bounding_span = Span::with_root_ctxt(lo, hi);
405 let lines = sm.span_to_lines(bounding_span).ok()?;
407 assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
408
409 if !sm.ensure_source_file_source_present(&lines.file) {
411 return None;
412 }
413
414 let mut highlights = vec![];
415 let sf = &lines.file;
425 let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
426 prev_hi.col = CharPos::from_usize(0);
427 let mut prev_line =
428 lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
429 let mut buf = String::new();
430
431 let mut line_highlight = vec![];
432 let mut acc = 0;
435 let mut confusion_type = ConfusionType::None;
436
437 let trimmed_parts = substitution
438 .parts
439 .into_iter()
440 .map(|part| part.trim_trivial_replacements(sm))
444 .collect::<Vec<_>>();
445
446 for part in &trimmed_parts {
447 let part_confusion = detect_confusion_type(sm, &part.snippet, part.span);
448 confusion_type = confusion_type.combine(part_confusion);
449 let cur_lo = sm.lookup_char_pos(part.span.lo());
450 if prev_hi.line == cur_lo.line {
451 let mut count =
452 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
453 while count > 0 {
454 highlights.push(std::mem::take(&mut line_highlight));
455 acc = 0;
456 count -= 1;
457 }
458 } else {
459 acc = 0;
460 highlights.push(std::mem::take(&mut line_highlight));
461 let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
462 while count > 0 {
463 highlights.push(std::mem::take(&mut line_highlight));
464 count -= 1;
465 }
466 for idx in prev_hi.line..(cur_lo.line - 1) {
468 if let Some(line) = sf.get_line(idx) {
469 buf.push_str(line.as_ref());
470 buf.push('\n');
471 highlights.push(std::mem::take(&mut line_highlight));
472 }
473 }
474 if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
475 let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
476 Some((i, _)) => i,
477 None => cur_line.len(),
478 };
479 buf.push_str(&cur_line[..end]);
480 }
481 }
482 let len: isize = part
484 .snippet
485 .split('\n')
486 .next()
487 .unwrap_or(&part.snippet)
488 .chars()
489 .map(|c| match c {
490 '\t' => 4,
491 _ => 1,
492 })
493 .sum();
494 if !is_different(sm, &part.snippet, part.span) {
495 } else {
499 line_highlight.push(SubstitutionHighlight {
500 start: (cur_lo.col.0 as isize + acc) as usize,
501 end: (cur_lo.col.0 as isize + acc + len) as usize,
502 });
503 }
504 buf.push_str(&part.snippet);
505 let cur_hi = sm.lookup_char_pos(part.span.hi());
506 acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
511 prev_hi = cur_hi;
512 prev_line = sf.get_line(prev_hi.line - 1);
513 for line in part.snippet.split('\n').skip(1) {
514 acc = 0;
515 highlights.push(std::mem::take(&mut line_highlight));
516 let end: usize = line
517 .chars()
518 .map(|c| match c {
519 '\t' => 4,
520 _ => 1,
521 })
522 .sum();
523 line_highlight.push(SubstitutionHighlight { start: 0, end });
524 }
525 }
526 highlights.push(std::mem::take(&mut line_highlight));
527 if !buf.ends_with('\n') {
529 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
530 }
531 while buf.ends_with('\n') {
533 buf.pop();
534 }
535 if highlights.iter().all(|parts| parts.is_empty()) {
536 None
537 } else {
538 Some((buf, trimmed_parts, highlights, confusion_type))
539 }
540 })
541 .collect()
542 }
543}
544
545pub struct ExplicitBug;
548
549pub struct DelayedBugPanic;
552
553pub struct DiagCtxt {
557 inner: Lock<DiagCtxtInner>,
558}
559
560#[derive(Copy, Clone)]
561pub struct DiagCtxtHandle<'a> {
562 dcx: &'a DiagCtxt,
563 tainted_with_errors: Option<&'a Cell<Option<ErrorGuaranteed>>>,
566}
567
568impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
569 type Target = &'a DiagCtxt;
570
571 fn deref(&self) -> &Self::Target {
572 &self.dcx
573 }
574}
575
576struct DiagCtxtInner {
580 flags: DiagCtxtFlags,
581
582 registry: Registry,
583
584 err_guars: Vec<ErrorGuaranteed>,
586 lint_err_guars: Vec<ErrorGuaranteed>,
589 delayed_bugs: Vec<(DelayedDiagInner, ErrorGuaranteed)>,
591
592 deduplicated_err_count: usize,
594 deduplicated_warn_count: usize,
596
597 emitter: Box<DynEmitter>,
598
599 must_produce_diag: Option<Backtrace>,
602
603 has_printed: bool,
606
607 suppressed_expected_diag: bool,
610
611 taught_diagnostics: FxHashSet<ErrCode>,
615
616 emitted_diagnostic_codes: FxIndexSet<ErrCode>,
618
619 emitted_diagnostics: FxHashSet<Hash128>,
623
624 stashed_diagnostics:
630 FxIndexMap<StashKey, FxIndexMap<Span, (DiagInner, Option<ErrorGuaranteed>)>>,
631
632 future_breakage_diagnostics: Vec<DiagInner>,
633
634 fulfilled_expectations: FxIndexSet<LintExpectationId>,
646
647 ice_file: Option<PathBuf>,
650}
651
652#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
654pub enum StashKey {
655 ItemNoType,
656 UnderscoreForArrayLengths,
657 EarlySyntaxWarning,
658 CallIntoMethod,
659 LifetimeIsChar,
662 MaybeFruTypo,
665 CallAssocMethod,
666 AssociatedTypeSuggestion,
667 Cycle,
669 UndeterminedMacroResolution,
670 ExprInPat,
672 GenericInFieldExpr,
676}
677
678fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
679 (*f)(diag)
680}
681
682pub static TRACK_DIAGNOSTIC: AtomicRef<
685 fn(DiagInner, &mut dyn FnMut(DiagInner) -> Option<ErrorGuaranteed>) -> Option<ErrorGuaranteed>,
686> = AtomicRef::new(&(default_track_diagnostic as _));
687
688#[derive(Copy, Clone, Default)]
689pub struct DiagCtxtFlags {
690 pub can_emit_warnings: bool,
693 pub treat_err_as_bug: Option<NonZero<usize>>,
696 pub eagerly_emit_delayed_bugs: bool,
699 pub macro_backtrace: bool,
702 pub deduplicate_diagnostics: bool,
704 pub track_diagnostics: bool,
706}
707
708impl Drop for DiagCtxtInner {
709 fn drop(&mut self) {
710 self.emit_stashed_diagnostics();
718
719 self.flush_delayed();
723
724 if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
728 if let Some(backtrace) = &self.must_produce_diag {
729 let suggestion = match backtrace.status() {
730 BacktraceStatus::Disabled => String::from(
731 "Backtraces are currently disabled: set `RUST_BACKTRACE=1` and re-run \
732 to see where it happened.",
733 ),
734 BacktraceStatus::Captured => format!(
735 "This happened in the following `must_produce_diag` call's backtrace:\n\
736 {backtrace}",
737 ),
738 _ => String::from("(impossible to capture backtrace where this happened)"),
739 };
740 panic!(
741 "`trimmed_def_paths` called, diagnostics were expected but none were emitted. \
742 Use `with_no_trimmed_paths` for debugging. {suggestion}"
743 );
744 }
745 }
746 }
747}
748
749impl DiagCtxt {
750 pub fn disable_warnings(mut self) -> Self {
751 self.inner.get_mut().flags.can_emit_warnings = false;
752 self
753 }
754
755 pub fn with_flags(mut self, flags: DiagCtxtFlags) -> Self {
756 self.inner.get_mut().flags = flags;
757 self
758 }
759
760 pub fn with_ice_file(mut self, ice_file: PathBuf) -> Self {
761 self.inner.get_mut().ice_file = Some(ice_file);
762 self
763 }
764
765 pub fn with_registry(mut self, registry: Registry) -> Self {
766 self.inner.get_mut().registry = registry;
767 self
768 }
769
770 pub fn new(emitter: Box<DynEmitter>) -> Self {
771 Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
772 }
773
774 pub fn make_silent(&self) {
775 let mut inner = self.inner.borrow_mut();
776 let translator = inner.emitter.translator().clone();
777 inner.emitter = Box::new(emitter::SilentEmitter { translator });
778 }
779
780 pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) {
781 self.inner.borrow_mut().emitter = emitter;
782 }
783
784 pub fn eagerly_translate<'a>(
786 &self,
787 message: DiagMessage,
788 args: impl Iterator<Item = DiagArg<'a>>,
789 ) -> SubdiagMessage {
790 let inner = self.inner.borrow();
791 inner.eagerly_translate(message, args)
792 }
793
794 pub fn eagerly_translate_to_string<'a>(
796 &self,
797 message: DiagMessage,
798 args: impl Iterator<Item = DiagArg<'a>>,
799 ) -> String {
800 let inner = self.inner.borrow();
801 inner.eagerly_translate_to_string(message, args)
802 }
803
804 pub fn can_emit_warnings(&self) -> bool {
808 self.inner.borrow_mut().flags.can_emit_warnings
809 }
810
811 pub fn reset_err_count(&self) {
817 let mut inner = self.inner.borrow_mut();
820 let DiagCtxtInner {
821 flags: _,
822 registry: _,
823 err_guars,
824 lint_err_guars,
825 delayed_bugs,
826 deduplicated_err_count,
827 deduplicated_warn_count,
828 emitter: _,
829 must_produce_diag,
830 has_printed,
831 suppressed_expected_diag,
832 taught_diagnostics,
833 emitted_diagnostic_codes,
834 emitted_diagnostics,
835 stashed_diagnostics,
836 future_breakage_diagnostics,
837 fulfilled_expectations,
838 ice_file: _,
839 } = inner.deref_mut();
840
841 *err_guars = Default::default();
844 *lint_err_guars = Default::default();
845 *delayed_bugs = Default::default();
846 *deduplicated_err_count = 0;
847 *deduplicated_warn_count = 0;
848 *must_produce_diag = None;
849 *has_printed = false;
850 *suppressed_expected_diag = false;
851 *taught_diagnostics = Default::default();
852 *emitted_diagnostic_codes = Default::default();
853 *emitted_diagnostics = Default::default();
854 *stashed_diagnostics = Default::default();
855 *future_breakage_diagnostics = Default::default();
856 *fulfilled_expectations = Default::default();
857 }
858
859 pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> {
860 DiagCtxtHandle { dcx: self, tainted_with_errors: None }
861 }
862
863 pub fn taintable_handle<'a>(
867 &'a self,
868 tainted_with_errors: &'a Cell<Option<ErrorGuaranteed>>,
869 ) -> DiagCtxtHandle<'a> {
870 DiagCtxtHandle { dcx: self, tainted_with_errors: Some(tainted_with_errors) }
871 }
872}
873
874impl<'a> DiagCtxtHandle<'a> {
875 pub fn stash_diagnostic(
897 &self,
898 span: Span,
899 key: StashKey,
900 diag: DiagInner,
901 ) -> Option<ErrorGuaranteed> {
902 let guar = match diag.level {
903 Bug | Fatal => {
904 self.span_bug(
905 span,
906 format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
907 );
908 }
909 Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
913 DelayedBug => {
914 return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors);
915 }
916 ForceWarning | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
917 | Expect => None,
918 };
919
920 self.inner
924 .borrow_mut()
925 .stashed_diagnostics
926 .entry(key)
927 .or_default()
928 .insert(span.with_parent(None), (diag, guar));
929
930 guar
931 }
932
933 pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
937 let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
939 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
940 )?;
941 assert!(!diag.is_error());
942 assert!(guar.is_none());
943 Some(Diag::new_diagnostic(self, diag))
944 }
945
946 pub fn try_steal_modify_and_emit_err<F>(
951 self,
952 span: Span,
953 key: StashKey,
954 mut modify_err: F,
955 ) -> Option<ErrorGuaranteed>
956 where
957 F: FnMut(&mut Diag<'_>),
958 {
959 let err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
961 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
962 );
963 err.map(|(err, guar)| {
964 assert_eq!(err.level, Error);
966 assert!(guar.is_some());
967 let mut err = Diag::<ErrorGuaranteed>::new_diagnostic(self, err);
968 modify_err(&mut err);
969 assert_eq!(err.level, Error);
970 err.emit()
971 })
972 }
973
974 pub fn try_steal_replace_and_emit_err(
978 self,
979 span: Span,
980 key: StashKey,
981 new_err: Diag<'_>,
982 ) -> ErrorGuaranteed {
983 let old_err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
985 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
986 );
987 match old_err {
988 Some((old_err, guar)) => {
989 assert_eq!(old_err.level, Error);
990 assert!(guar.is_some());
991 Diag::<ErrorGuaranteed>::new_diagnostic(self, old_err).cancel();
994 }
995 None => {}
996 };
997 new_err.emit()
998 }
999
1000 pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
1001 let inner = self.inner.borrow();
1002 if let Some(stashed_diagnostics) = inner.stashed_diagnostics.get(&key)
1003 && !stashed_diagnostics.is_empty()
1004 {
1005 stashed_diagnostics.contains_key(&span.with_parent(None))
1006 } else {
1007 false
1008 }
1009 }
1010
1011 pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
1013 self.inner.borrow_mut().emit_stashed_diagnostics()
1014 }
1015
1016 #[inline]
1018 pub fn err_count(&self) -> usize {
1019 let inner = self.inner.borrow();
1020 inner.err_guars.len()
1021 + inner.lint_err_guars.len()
1022 + inner
1023 .stashed_diagnostics
1024 .values()
1025 .map(|a| a.values().filter(|(_, guar)| guar.is_some()).count())
1026 .sum::<usize>()
1027 }
1028
1029 pub fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1032 self.inner.borrow().has_errors_excluding_lint_errors()
1033 }
1034
1035 pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
1037 self.inner.borrow().has_errors()
1038 }
1039
1040 pub fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1043 self.inner.borrow().has_errors_or_delayed_bugs()
1044 }
1045
1046 pub fn print_error_count(&self) {
1047 let mut inner = self.inner.borrow_mut();
1048
1049 assert!(inner.stashed_diagnostics.is_empty());
1052
1053 if inner.treat_err_as_bug() {
1054 return;
1055 }
1056
1057 let warnings = match inner.deduplicated_warn_count {
1058 0 => Cow::from(""),
1059 1 => Cow::from("1 warning emitted"),
1060 count => Cow::from(format!("{count} warnings emitted")),
1061 };
1062 let errors = match inner.deduplicated_err_count {
1063 0 => Cow::from(""),
1064 1 => Cow::from("aborting due to 1 previous error"),
1065 count => Cow::from(format!("aborting due to {count} previous errors")),
1066 };
1067
1068 match (errors.len(), warnings.len()) {
1069 (0, 0) => return,
1070 (0, _) => {
1071 inner.emit_diagnostic(
1074 DiagInner::new(ForceWarning, DiagMessage::Str(warnings)),
1075 None,
1076 );
1077 }
1078 (_, 0) => {
1079 inner.emit_diagnostic(DiagInner::new(Error, errors), self.tainted_with_errors);
1080 }
1081 (_, _) => {
1082 inner.emit_diagnostic(
1083 DiagInner::new(Error, format!("{errors}; {warnings}")),
1084 self.tainted_with_errors,
1085 );
1086 }
1087 }
1088
1089 let can_show_explain = inner.emitter.should_show_explain();
1090 let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty();
1091 if can_show_explain && are_there_diagnostics {
1092 let mut error_codes = inner
1093 .emitted_diagnostic_codes
1094 .iter()
1095 .filter_map(|&code| {
1096 if inner.registry.try_find_description(code).is_ok() {
1097 Some(code.to_string())
1098 } else {
1099 None
1100 }
1101 })
1102 .collect::<Vec<_>>();
1103 if !error_codes.is_empty() {
1104 error_codes.sort();
1105 if error_codes.len() > 1 {
1106 let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
1107 let msg1 = format!(
1108 "Some errors have detailed explanations: {}{}",
1109 error_codes[..limit].join(", "),
1110 if error_codes.len() > 9 { "..." } else { "." }
1111 );
1112 let msg2 = format!(
1113 "For more information about an error, try `rustc --explain {}`.",
1114 &error_codes[0]
1115 );
1116 inner.emit_diagnostic(DiagInner::new(FailureNote, msg1), None);
1117 inner.emit_diagnostic(DiagInner::new(FailureNote, msg2), None);
1118 } else {
1119 let msg = format!(
1120 "For more information about this error, try `rustc --explain {}`.",
1121 &error_codes[0]
1122 );
1123 inner.emit_diagnostic(DiagInner::new(FailureNote, msg), None);
1124 }
1125 }
1126 }
1127 }
1128
1129 pub fn abort_if_errors(&self) {
1134 if let Some(guar) = self.has_errors() {
1135 guar.raise_fatal();
1136 }
1137 }
1138
1139 pub fn must_teach(&self, code: ErrCode) -> bool {
1145 self.inner.borrow_mut().taught_diagnostics.insert(code)
1146 }
1147
1148 pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
1149 self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors)
1150 }
1151
1152 pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
1153 self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
1154 }
1155
1156 pub fn emit_timing_section_start(&self, record: TimingRecord) {
1157 self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::Start);
1158 }
1159
1160 pub fn emit_timing_section_end(&self, record: TimingRecord) {
1161 self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::End);
1162 }
1163
1164 pub fn emit_future_breakage_report(&self) {
1165 let inner = &mut *self.inner.borrow_mut();
1166 let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
1167 if !diags.is_empty() {
1168 inner.emitter.emit_future_breakage_report(diags, &inner.registry);
1169 }
1170 }
1171
1172 pub fn emit_unused_externs(
1173 &self,
1174 lint_level: rustc_lint_defs::Level,
1175 loud: bool,
1176 unused_externs: &[&str],
1177 ) {
1178 let mut inner = self.inner.borrow_mut();
1179
1180 if loud && lint_level.is_error() {
1191 #[allow(deprecated)]
1194 inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
1195 inner.panic_if_treat_err_as_bug();
1196 }
1197
1198 inner.emitter.emit_unused_externs(lint_level, unused_externs)
1199 }
1200
1201 #[must_use]
1204 pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
1205 std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
1206 }
1207
1208 pub fn flush_delayed(&self) {
1209 self.inner.borrow_mut().flush_delayed();
1210 }
1211
1212 #[track_caller]
1215 pub fn set_must_produce_diag(&self) {
1216 assert!(
1217 self.inner.borrow().must_produce_diag.is_none(),
1218 "should only need to collect a backtrace once"
1219 );
1220 self.inner.borrow_mut().must_produce_diag = Some(Backtrace::capture());
1221 }
1222}
1223
1224impl<'a> DiagCtxtHandle<'a> {
1229 #[track_caller]
1232 pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> {
1233 Diag::new(self, Bug, msg.into())
1234 }
1235
1236 #[track_caller]
1239 pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
1240 self.struct_bug(msg).emit()
1241 }
1242
1243 #[track_caller]
1246 pub fn struct_span_bug(
1247 self,
1248 span: impl Into<MultiSpan>,
1249 msg: impl Into<Cow<'static, str>>,
1250 ) -> Diag<'a, BugAbort> {
1251 self.struct_bug(msg).with_span(span)
1252 }
1253
1254 #[track_caller]
1257 pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
1258 self.struct_span_bug(span, msg.into()).emit()
1259 }
1260
1261 #[track_caller]
1262 pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> {
1263 bug.into_diag(self, Bug)
1264 }
1265
1266 #[track_caller]
1267 pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! {
1268 self.create_bug(bug).emit()
1269 }
1270
1271 #[rustc_lint_diagnostics]
1272 #[track_caller]
1273 pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> {
1274 Diag::new(self, Fatal, msg)
1275 }
1276
1277 #[rustc_lint_diagnostics]
1278 #[track_caller]
1279 pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
1280 self.struct_fatal(msg).emit()
1281 }
1282
1283 #[rustc_lint_diagnostics]
1284 #[track_caller]
1285 pub fn struct_span_fatal(
1286 self,
1287 span: impl Into<MultiSpan>,
1288 msg: impl Into<DiagMessage>,
1289 ) -> Diag<'a, FatalAbort> {
1290 self.struct_fatal(msg).with_span(span)
1291 }
1292
1293 #[rustc_lint_diagnostics]
1294 #[track_caller]
1295 pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
1296 self.struct_span_fatal(span, msg).emit()
1297 }
1298
1299 #[track_caller]
1300 pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> {
1301 fatal.into_diag(self, Fatal)
1302 }
1303
1304 #[track_caller]
1305 pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
1306 self.create_fatal(fatal).emit()
1307 }
1308
1309 #[track_caller]
1310 pub fn create_almost_fatal(
1311 self,
1312 fatal: impl Diagnostic<'a, FatalError>,
1313 ) -> Diag<'a, FatalError> {
1314 fatal.into_diag(self, Fatal)
1315 }
1316
1317 #[track_caller]
1318 pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError {
1319 self.create_almost_fatal(fatal).emit()
1320 }
1321
1322 #[rustc_lint_diagnostics]
1324 #[track_caller]
1325 pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> {
1326 Diag::new(self, Error, msg)
1327 }
1328
1329 #[rustc_lint_diagnostics]
1330 #[track_caller]
1331 pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
1332 self.struct_err(msg).emit()
1333 }
1334
1335 #[rustc_lint_diagnostics]
1336 #[track_caller]
1337 pub fn struct_span_err(
1338 self,
1339 span: impl Into<MultiSpan>,
1340 msg: impl Into<DiagMessage>,
1341 ) -> Diag<'a> {
1342 self.struct_err(msg).with_span(span)
1343 }
1344
1345 #[rustc_lint_diagnostics]
1346 #[track_caller]
1347 pub fn span_err(
1348 self,
1349 span: impl Into<MultiSpan>,
1350 msg: impl Into<DiagMessage>,
1351 ) -> ErrorGuaranteed {
1352 self.struct_span_err(span, msg).emit()
1353 }
1354
1355 #[track_caller]
1356 pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> {
1357 err.into_diag(self, Error)
1358 }
1359
1360 #[track_caller]
1361 pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
1362 self.create_err(err).emit()
1363 }
1364
1365 #[track_caller]
1370 pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
1371 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
1372 }
1373
1374 #[track_caller]
1382 pub fn span_delayed_bug(
1383 self,
1384 sp: impl Into<MultiSpan>,
1385 msg: impl Into<Cow<'static, str>>,
1386 ) -> ErrorGuaranteed {
1387 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
1388 }
1389
1390 #[rustc_lint_diagnostics]
1391 #[track_caller]
1392 pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1393 Diag::new(self, Warning, msg)
1394 }
1395
1396 #[rustc_lint_diagnostics]
1397 #[track_caller]
1398 pub fn warn(self, msg: impl Into<DiagMessage>) {
1399 self.struct_warn(msg).emit()
1400 }
1401
1402 #[rustc_lint_diagnostics]
1403 #[track_caller]
1404 pub fn struct_span_warn(
1405 self,
1406 span: impl Into<MultiSpan>,
1407 msg: impl Into<DiagMessage>,
1408 ) -> Diag<'a, ()> {
1409 self.struct_warn(msg).with_span(span)
1410 }
1411
1412 #[rustc_lint_diagnostics]
1413 #[track_caller]
1414 pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1415 self.struct_span_warn(span, msg).emit()
1416 }
1417
1418 #[track_caller]
1419 pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1420 warning.into_diag(self, Warning)
1421 }
1422
1423 #[track_caller]
1424 pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) {
1425 self.create_warn(warning).emit()
1426 }
1427
1428 #[rustc_lint_diagnostics]
1429 #[track_caller]
1430 pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1431 Diag::new(self, Note, msg)
1432 }
1433
1434 #[rustc_lint_diagnostics]
1435 #[track_caller]
1436 pub fn note(&self, msg: impl Into<DiagMessage>) {
1437 self.struct_note(msg).emit()
1438 }
1439
1440 #[rustc_lint_diagnostics]
1441 #[track_caller]
1442 pub fn struct_span_note(
1443 self,
1444 span: impl Into<MultiSpan>,
1445 msg: impl Into<DiagMessage>,
1446 ) -> Diag<'a, ()> {
1447 self.struct_note(msg).with_span(span)
1448 }
1449
1450 #[rustc_lint_diagnostics]
1451 #[track_caller]
1452 pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1453 self.struct_span_note(span, msg).emit()
1454 }
1455
1456 #[track_caller]
1457 pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1458 note.into_diag(self, Note)
1459 }
1460
1461 #[track_caller]
1462 pub fn emit_note(self, note: impl Diagnostic<'a, ()>) {
1463 self.create_note(note).emit()
1464 }
1465
1466 #[rustc_lint_diagnostics]
1467 #[track_caller]
1468 pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1469 Diag::new(self, Help, msg)
1470 }
1471
1472 #[rustc_lint_diagnostics]
1473 #[track_caller]
1474 pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1475 Diag::new(self, FailureNote, msg)
1476 }
1477
1478 #[rustc_lint_diagnostics]
1479 #[track_caller]
1480 pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1481 Diag::new(self, Allow, msg)
1482 }
1483
1484 #[rustc_lint_diagnostics]
1485 #[track_caller]
1486 pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> {
1487 Diag::new(self, Expect, msg).with_lint_id(id)
1488 }
1489}
1490
1491impl DiagCtxtInner {
1496 fn new(emitter: Box<DynEmitter>) -> Self {
1497 Self {
1498 flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
1499 registry: Registry::new(&[]),
1500 err_guars: Vec::new(),
1501 lint_err_guars: Vec::new(),
1502 delayed_bugs: Vec::new(),
1503 deduplicated_err_count: 0,
1504 deduplicated_warn_count: 0,
1505 emitter,
1506 must_produce_diag: None,
1507 has_printed: false,
1508 suppressed_expected_diag: false,
1509 taught_diagnostics: Default::default(),
1510 emitted_diagnostic_codes: Default::default(),
1511 emitted_diagnostics: Default::default(),
1512 stashed_diagnostics: Default::default(),
1513 future_breakage_diagnostics: Vec::new(),
1514 fulfilled_expectations: Default::default(),
1515 ice_file: None,
1516 }
1517 }
1518
1519 fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
1521 let mut guar = None;
1522 let has_errors = !self.err_guars.is_empty();
1523 for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
1524 for (_, (diag, _guar)) in stashed_diagnostics {
1525 if !diag.is_error() {
1526 if !diag.is_force_warn() && has_errors {
1530 continue;
1531 }
1532 }
1533 guar = guar.or(self.emit_diagnostic(diag, None));
1534 }
1535 }
1536 guar
1537 }
1538
1539 fn emit_diagnostic(
1541 &mut self,
1542 mut diagnostic: DiagInner,
1543 taint: Option<&Cell<Option<ErrorGuaranteed>>>,
1544 ) -> Option<ErrorGuaranteed> {
1545 if diagnostic.has_future_breakage() {
1546 assert_matches!(diagnostic.level, Error | ForceWarning | Warning | Allow | Expect);
1550 self.future_breakage_diagnostics.push(diagnostic.clone());
1551 }
1552
1553 match diagnostic.level {
1557 Bug => {}
1558 Fatal | Error => {
1559 if self.treat_next_err_as_bug() {
1560 diagnostic.level = Bug;
1562 }
1563 }
1564 DelayedBug => {
1565 if self.flags.eagerly_emit_delayed_bugs {
1570 if self.treat_next_err_as_bug() {
1572 diagnostic.level = Bug;
1573 } else {
1574 diagnostic.level = Error;
1575 }
1576 } else {
1577 return if let Some(guar) = self.has_errors() {
1580 Some(guar)
1581 } else {
1582 let backtrace = std::backtrace::Backtrace::capture();
1586 #[allow(deprecated)]
1590 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1591 self.delayed_bugs
1592 .push((DelayedDiagInner::with_backtrace(diagnostic, backtrace), guar));
1593 Some(guar)
1594 };
1595 }
1596 }
1597 ForceWarning if diagnostic.lint_id.is_none() => {} Warning => {
1599 if !self.flags.can_emit_warnings {
1600 if diagnostic.has_future_breakage() {
1602 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1604 }
1605 return None;
1606 }
1607 }
1608 Note | Help | FailureNote => {}
1609 OnceNote | OnceHelp => panic!("bad level: {:?}", diagnostic.level),
1610 Allow => {
1611 if diagnostic.has_future_breakage() {
1613 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1615 self.suppressed_expected_diag = true;
1616 }
1617 return None;
1618 }
1619 Expect | ForceWarning => {
1620 self.fulfilled_expectations.insert(diagnostic.lint_id.unwrap());
1621 if let Expect = diagnostic.level {
1622 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1624 self.suppressed_expected_diag = true;
1625 return None;
1626 }
1627 }
1628 }
1629
1630 TRACK_DIAGNOSTIC(diagnostic, &mut |mut diagnostic| {
1631 if let Some(code) = diagnostic.code {
1632 self.emitted_diagnostic_codes.insert(code);
1633 }
1634
1635 let already_emitted = {
1636 let mut hasher = StableHasher::new();
1637 diagnostic.hash(&mut hasher);
1638 let diagnostic_hash = hasher.finish();
1639 !self.emitted_diagnostics.insert(diagnostic_hash)
1640 };
1641
1642 let is_error = diagnostic.is_error();
1643 let is_lint = diagnostic.is_lint.is_some();
1644
1645 if !(self.flags.deduplicate_diagnostics && already_emitted) {
1648 debug!(?diagnostic);
1649 debug!(?self.emitted_diagnostics);
1650
1651 let not_yet_emitted = |sub: &mut Subdiag| {
1652 debug!(?sub);
1653 if sub.level != OnceNote && sub.level != OnceHelp {
1654 return true;
1655 }
1656 let mut hasher = StableHasher::new();
1657 sub.hash(&mut hasher);
1658 let diagnostic_hash = hasher.finish();
1659 debug!(?diagnostic_hash);
1660 self.emitted_diagnostics.insert(diagnostic_hash)
1661 };
1662 diagnostic.children.retain_mut(not_yet_emitted);
1663 if already_emitted {
1664 let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`";
1665 diagnostic.sub(Note, msg, MultiSpan::new());
1666 }
1667
1668 if is_error {
1669 self.deduplicated_err_count += 1;
1670 } else if matches!(diagnostic.level, ForceWarning | Warning) {
1671 self.deduplicated_warn_count += 1;
1672 }
1673 self.has_printed = true;
1674
1675 self.emitter.emit_diagnostic(diagnostic, &self.registry);
1676 }
1677
1678 if is_error {
1679 if !self.delayed_bugs.is_empty() {
1684 assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0);
1685 self.delayed_bugs.clear();
1686 self.delayed_bugs.shrink_to_fit();
1687 }
1688
1689 #[allow(deprecated)]
1692 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1693 if is_lint {
1694 self.lint_err_guars.push(guar);
1695 } else {
1696 if let Some(taint) = taint {
1697 taint.set(Some(guar));
1698 }
1699 self.err_guars.push(guar);
1700 }
1701 self.panic_if_treat_err_as_bug();
1702 Some(guar)
1703 } else {
1704 None
1705 }
1706 })
1707 }
1708
1709 fn treat_err_as_bug(&self) -> bool {
1710 self.flags
1711 .treat_err_as_bug
1712 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
1713 }
1714
1715 fn treat_next_err_as_bug(&self) -> bool {
1717 self.flags
1718 .treat_err_as_bug
1719 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
1720 }
1721
1722 fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1723 self.err_guars.get(0).copied().or_else(|| {
1724 if let Some((_diag, guar)) = self
1725 .stashed_diagnostics
1726 .values()
1727 .flat_map(|stashed_diagnostics| stashed_diagnostics.values())
1728 .find(|(diag, guar)| guar.is_some() && diag.is_lint.is_none())
1729 {
1730 *guar
1731 } else {
1732 None
1733 }
1734 })
1735 }
1736
1737 fn has_errors(&self) -> Option<ErrorGuaranteed> {
1738 self.err_guars.get(0).copied().or_else(|| self.lint_err_guars.get(0).copied()).or_else(
1739 || {
1740 self.stashed_diagnostics.values().find_map(|stashed_diagnostics| {
1741 stashed_diagnostics.values().find_map(|(_, guar)| *guar)
1742 })
1743 },
1744 )
1745 }
1746
1747 fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1748 self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
1749 }
1750
1751 fn eagerly_translate<'a>(
1753 &self,
1754 message: DiagMessage,
1755 args: impl Iterator<Item = DiagArg<'a>>,
1756 ) -> SubdiagMessage {
1757 SubdiagMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
1758 }
1759
1760 fn eagerly_translate_to_string<'a>(
1762 &self,
1763 message: DiagMessage,
1764 args: impl Iterator<Item = DiagArg<'a>>,
1765 ) -> String {
1766 let args = crate::translation::to_fluent_args(args);
1767 self.emitter
1768 .translator()
1769 .translate_message(&message, &args)
1770 .map_err(Report::new)
1771 .unwrap()
1772 .to_string()
1773 }
1774
1775 fn eagerly_translate_for_subdiag(
1776 &self,
1777 diag: &DiagInner,
1778 msg: impl Into<SubdiagMessage>,
1779 ) -> SubdiagMessage {
1780 let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
1781 self.eagerly_translate(msg, diag.args.iter())
1782 }
1783
1784 fn flush_delayed(&mut self) {
1785 assert!(self.stashed_diagnostics.is_empty());
1789
1790 if !self.err_guars.is_empty() {
1791 return;
1793 }
1794
1795 if self.delayed_bugs.is_empty() {
1796 return;
1798 }
1799
1800 let bugs: Vec<_> =
1801 std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
1802
1803 let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0"));
1804 let decorate = backtrace || self.ice_file.is_none();
1805 let mut out = self
1806 .ice_file
1807 .as_ref()
1808 .and_then(|file| std::fs::File::options().create(true).append(true).open(file).ok());
1809
1810 let note1 = "no errors encountered even though delayed bugs were created";
1815 let note2 = "those delayed bugs will now be shown as internal compiler errors";
1816 self.emit_diagnostic(DiagInner::new(Note, note1), None);
1817 self.emit_diagnostic(DiagInner::new(Note, note2), None);
1818
1819 for bug in bugs {
1820 if let Some(out) = &mut out {
1821 _ = write!(
1822 out,
1823 "delayed bug: {}\n{}\n",
1824 bug.inner
1825 .messages
1826 .iter()
1827 .filter_map(|(msg, _)| msg.as_str())
1828 .collect::<String>(),
1829 &bug.note
1830 );
1831 }
1832
1833 let mut bug = if decorate { bug.decorate(self) } else { bug.inner };
1834
1835 if bug.level != DelayedBug {
1837 bug.arg("level", bug.level);
1844 let msg = crate::fluent_generated::errors_invalid_flushed_delayed_diagnostic_level;
1845 let msg = self.eagerly_translate_for_subdiag(&bug, msg); bug.sub(Note, msg, bug.span.primary_span().unwrap().into());
1847 }
1848 bug.level = Bug;
1849
1850 self.emit_diagnostic(bug, None);
1851 }
1852
1853 panic::panic_any(DelayedBugPanic);
1855 }
1856
1857 fn panic_if_treat_err_as_bug(&self) {
1858 if self.treat_err_as_bug() {
1859 let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
1860 assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
1861 if n == 1 {
1862 panic!("aborting due to `-Z treat-err-as-bug=1`");
1863 } else {
1864 panic!("aborting after {n} errors due to `-Z treat-err-as-bug={n}`");
1865 }
1866 }
1867 }
1868}
1869
1870struct DelayedDiagInner {
1871 inner: DiagInner,
1872 note: Backtrace,
1873}
1874
1875impl DelayedDiagInner {
1876 fn with_backtrace(diagnostic: DiagInner, backtrace: Backtrace) -> Self {
1877 DelayedDiagInner { inner: diagnostic, note: backtrace }
1878 }
1879
1880 fn decorate(self, dcx: &DiagCtxtInner) -> DiagInner {
1881 let mut diag = self.inner;
1885 let msg = match self.note.status() {
1886 BacktraceStatus::Captured => crate::fluent_generated::errors_delayed_at_with_newline,
1887 _ => crate::fluent_generated::errors_delayed_at_without_newline,
1890 };
1891 diag.arg("emitted_at", diag.emitted_at.clone());
1892 diag.arg("note", self.note);
1893 let msg = dcx.eagerly_translate_for_subdiag(&diag, msg); diag.sub(Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into());
1895 diag
1896 }
1897}
1898
1899#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
1919pub enum Level {
1920 Bug,
1922
1923 Fatal,
1926
1927 Error,
1930
1931 DelayedBug,
1936
1937 ForceWarning,
1943
1944 Warning,
1947
1948 Note,
1950
1951 OnceNote,
1953
1954 Help,
1956
1957 OnceHelp,
1959
1960 FailureNote,
1963
1964 Allow,
1966
1967 Expect,
1969}
1970
1971impl fmt::Display for Level {
1972 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1973 self.to_str().fmt(f)
1974 }
1975}
1976
1977impl Level {
1978 fn color(self) -> anstyle::Style {
1979 match self {
1980 Bug | Fatal | Error | DelayedBug => AnsiColor::BrightRed.on_default(),
1981 ForceWarning | Warning => {
1982 if cfg!(windows) {
1983 AnsiColor::BrightYellow.on_default()
1984 } else {
1985 AnsiColor::Yellow.on_default()
1986 }
1987 }
1988 Note | OnceNote => AnsiColor::BrightGreen.on_default(),
1989 Help | OnceHelp => AnsiColor::BrightCyan.on_default(),
1990 FailureNote => anstyle::Style::new(),
1991 Allow | Expect => unreachable!(),
1992 }
1993 }
1994
1995 pub fn to_str(self) -> &'static str {
1996 match self {
1997 Bug | DelayedBug => "error: internal compiler error",
1998 Fatal | Error => "error",
1999 ForceWarning | Warning => "warning",
2000 Note | OnceNote => "note",
2001 Help | OnceHelp => "help",
2002 FailureNote => "failure-note",
2003 Allow | Expect => unreachable!(),
2004 }
2005 }
2006
2007 pub fn is_failure_note(&self) -> bool {
2008 matches!(*self, FailureNote)
2009 }
2010
2011 fn can_be_subdiag(&self) -> bool {
2013 match self {
2014 Bug | DelayedBug | Fatal | Error | ForceWarning | FailureNote | Allow | Expect => false,
2015
2016 Warning | Note | Help | OnceNote | OnceHelp => true,
2017 }
2018 }
2019}
2020
2021impl IntoDiagArg for Level {
2022 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
2023 DiagArgValue::Str(Cow::from(self.to_string()))
2024 }
2025}
2026
2027pub fn elided_lifetime_in_path_suggestion(
2029 source_map: &SourceMap,
2030 n: usize,
2031 path_span: Span,
2032 incl_angl_brckt: bool,
2033 insertion_span: Span,
2034) -> ElidedLifetimeInPathSubdiag {
2035 let expected = ExpectedLifetimeParameter { span: path_span, count: n };
2036 let indicate = source_map.is_span_accessible(insertion_span).then(|| {
2038 let anon_lts = vec!["'_"; n].join(", ");
2039 let suggestion =
2040 if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
2041
2042 IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
2043 });
2044
2045 ElidedLifetimeInPathSubdiag { expected, indicate }
2046}
2047
2048pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
2049 diag: &mut Diag<'a, G>,
2050 ambiguity: rustc_lint_defs::AmbiguityErrorDiag,
2051) {
2052 diag.span_label(ambiguity.label_span, ambiguity.label_msg);
2053 diag.note(ambiguity.note_msg);
2054 diag.span_note(ambiguity.b1_span, ambiguity.b1_note_msg);
2055 for help_msg in ambiguity.b1_help_msgs {
2056 diag.help(help_msg);
2057 }
2058 diag.span_note(ambiguity.b2_span, ambiguity.b2_note_msg);
2059 for help_msg in ambiguity.b2_help_msgs {
2060 diag.help(help_msg);
2061 }
2062}
2063
2064pub fn a_or_an(s: &str) -> &'static str {
2068 let mut chars = s.chars();
2069 let Some(mut first_alpha_char) = chars.next() else {
2070 return "a";
2071 };
2072 if first_alpha_char == '`' {
2073 let Some(next) = chars.next() else {
2074 return "a";
2075 };
2076 first_alpha_char = next;
2077 }
2078 if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
2079 "an"
2080 } else {
2081 "a"
2082 }
2083}
2084
2085#[derive(Clone, Copy, PartialEq, Hash, Debug)]
2086pub enum TerminalUrl {
2087 No,
2088 Yes,
2089 Auto,
2090}