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) {
1213 self.inner.borrow_mut().flush_delayed();
1214 }
1215
1216 #[track_caller]
1219 pub fn set_must_produce_diag(&self) {
1220 assert!(
1221 self.inner.borrow().must_produce_diag.is_none(),
1222 "should only need to collect a backtrace once"
1223 );
1224 self.inner.borrow_mut().must_produce_diag = Some(Backtrace::capture());
1225 }
1226}
1227
1228impl<'a> DiagCtxtHandle<'a> {
1233 #[track_caller]
1236 pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> {
1237 Diag::new(self, Bug, msg.into())
1238 }
1239
1240 #[track_caller]
1243 pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
1244 self.struct_bug(msg).emit()
1245 }
1246
1247 #[track_caller]
1250 pub fn struct_span_bug(
1251 self,
1252 span: impl Into<MultiSpan>,
1253 msg: impl Into<Cow<'static, str>>,
1254 ) -> Diag<'a, BugAbort> {
1255 self.struct_bug(msg).with_span(span)
1256 }
1257
1258 #[track_caller]
1261 pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
1262 self.struct_span_bug(span, msg.into()).emit()
1263 }
1264
1265 #[track_caller]
1266 pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> {
1267 bug.into_diag(self, Bug)
1268 }
1269
1270 #[track_caller]
1271 pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! {
1272 self.create_bug(bug).emit()
1273 }
1274
1275 #[rustc_lint_diagnostics]
1276 #[track_caller]
1277 pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> {
1278 Diag::new(self, Fatal, msg)
1279 }
1280
1281 #[rustc_lint_diagnostics]
1282 #[track_caller]
1283 pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
1284 self.struct_fatal(msg).emit()
1285 }
1286
1287 #[rustc_lint_diagnostics]
1288 #[track_caller]
1289 pub fn struct_span_fatal(
1290 self,
1291 span: impl Into<MultiSpan>,
1292 msg: impl Into<DiagMessage>,
1293 ) -> Diag<'a, FatalAbort> {
1294 self.struct_fatal(msg).with_span(span)
1295 }
1296
1297 #[rustc_lint_diagnostics]
1298 #[track_caller]
1299 pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
1300 self.struct_span_fatal(span, msg).emit()
1301 }
1302
1303 #[track_caller]
1304 pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> {
1305 fatal.into_diag(self, Fatal)
1306 }
1307
1308 #[track_caller]
1309 pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
1310 self.create_fatal(fatal).emit()
1311 }
1312
1313 #[track_caller]
1314 pub fn create_almost_fatal(
1315 self,
1316 fatal: impl Diagnostic<'a, FatalError>,
1317 ) -> Diag<'a, FatalError> {
1318 fatal.into_diag(self, Fatal)
1319 }
1320
1321 #[track_caller]
1322 pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError {
1323 self.create_almost_fatal(fatal).emit()
1324 }
1325
1326 #[rustc_lint_diagnostics]
1328 #[track_caller]
1329 pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> {
1330 Diag::new(self, Error, msg)
1331 }
1332
1333 #[rustc_lint_diagnostics]
1334 #[track_caller]
1335 pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
1336 self.struct_err(msg).emit()
1337 }
1338
1339 #[rustc_lint_diagnostics]
1340 #[track_caller]
1341 pub fn struct_span_err(
1342 self,
1343 span: impl Into<MultiSpan>,
1344 msg: impl Into<DiagMessage>,
1345 ) -> Diag<'a> {
1346 self.struct_err(msg).with_span(span)
1347 }
1348
1349 #[rustc_lint_diagnostics]
1350 #[track_caller]
1351 pub fn span_err(
1352 self,
1353 span: impl Into<MultiSpan>,
1354 msg: impl Into<DiagMessage>,
1355 ) -> ErrorGuaranteed {
1356 self.struct_span_err(span, msg).emit()
1357 }
1358
1359 #[track_caller]
1360 pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> {
1361 err.into_diag(self, Error)
1362 }
1363
1364 #[track_caller]
1365 pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
1366 self.create_err(err).emit()
1367 }
1368
1369 #[track_caller]
1374 pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
1375 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
1376 }
1377
1378 #[track_caller]
1386 pub fn span_delayed_bug(
1387 self,
1388 sp: impl Into<MultiSpan>,
1389 msg: impl Into<Cow<'static, str>>,
1390 ) -> ErrorGuaranteed {
1391 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
1392 }
1393
1394 #[rustc_lint_diagnostics]
1395 #[track_caller]
1396 pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1397 Diag::new(self, Warning, msg)
1398 }
1399
1400 #[rustc_lint_diagnostics]
1401 #[track_caller]
1402 pub fn warn(self, msg: impl Into<DiagMessage>) {
1403 self.struct_warn(msg).emit()
1404 }
1405
1406 #[rustc_lint_diagnostics]
1407 #[track_caller]
1408 pub fn struct_span_warn(
1409 self,
1410 span: impl Into<MultiSpan>,
1411 msg: impl Into<DiagMessage>,
1412 ) -> Diag<'a, ()> {
1413 self.struct_warn(msg).with_span(span)
1414 }
1415
1416 #[rustc_lint_diagnostics]
1417 #[track_caller]
1418 pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1419 self.struct_span_warn(span, msg).emit()
1420 }
1421
1422 #[track_caller]
1423 pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1424 warning.into_diag(self, Warning)
1425 }
1426
1427 #[track_caller]
1428 pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) {
1429 self.create_warn(warning).emit()
1430 }
1431
1432 #[rustc_lint_diagnostics]
1433 #[track_caller]
1434 pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1435 Diag::new(self, Note, msg)
1436 }
1437
1438 #[rustc_lint_diagnostics]
1439 #[track_caller]
1440 pub fn note(&self, msg: impl Into<DiagMessage>) {
1441 self.struct_note(msg).emit()
1442 }
1443
1444 #[rustc_lint_diagnostics]
1445 #[track_caller]
1446 pub fn struct_span_note(
1447 self,
1448 span: impl Into<MultiSpan>,
1449 msg: impl Into<DiagMessage>,
1450 ) -> Diag<'a, ()> {
1451 self.struct_note(msg).with_span(span)
1452 }
1453
1454 #[rustc_lint_diagnostics]
1455 #[track_caller]
1456 pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1457 self.struct_span_note(span, msg).emit()
1458 }
1459
1460 #[track_caller]
1461 pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1462 note.into_diag(self, Note)
1463 }
1464
1465 #[track_caller]
1466 pub fn emit_note(self, note: impl Diagnostic<'a, ()>) {
1467 self.create_note(note).emit()
1468 }
1469
1470 #[rustc_lint_diagnostics]
1471 #[track_caller]
1472 pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1473 Diag::new(self, Help, msg)
1474 }
1475
1476 #[rustc_lint_diagnostics]
1477 #[track_caller]
1478 pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1479 Diag::new(self, FailureNote, msg)
1480 }
1481
1482 #[rustc_lint_diagnostics]
1483 #[track_caller]
1484 pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1485 Diag::new(self, Allow, msg)
1486 }
1487
1488 #[rustc_lint_diagnostics]
1489 #[track_caller]
1490 pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> {
1491 Diag::new(self, Expect, msg).with_lint_id(id)
1492 }
1493}
1494
1495impl DiagCtxtInner {
1500 fn new(emitter: Box<DynEmitter>) -> Self {
1501 Self {
1502 flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
1503 registry: Registry::new(&[]),
1504 err_guars: Vec::new(),
1505 lint_err_guars: Vec::new(),
1506 delayed_bugs: Vec::new(),
1507 deduplicated_err_count: 0,
1508 deduplicated_warn_count: 0,
1509 emitter,
1510 must_produce_diag: None,
1511 has_printed: false,
1512 suppressed_expected_diag: false,
1513 taught_diagnostics: Default::default(),
1514 emitted_diagnostic_codes: Default::default(),
1515 emitted_diagnostics: Default::default(),
1516 stashed_diagnostics: Default::default(),
1517 future_breakage_diagnostics: Vec::new(),
1518 fulfilled_expectations: Default::default(),
1519 ice_file: None,
1520 }
1521 }
1522
1523 fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
1525 let mut guar = None;
1526 let has_errors = !self.err_guars.is_empty();
1527 for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
1528 for (_, (diag, _guar)) in stashed_diagnostics {
1529 if !diag.is_error() {
1530 if !diag.is_force_warn() && has_errors {
1534 continue;
1535 }
1536 }
1537 guar = guar.or(self.emit_diagnostic(diag, None));
1538 }
1539 }
1540 guar
1541 }
1542
1543 fn emit_diagnostic(
1545 &mut self,
1546 mut diagnostic: DiagInner,
1547 taint: Option<&Cell<Option<ErrorGuaranteed>>>,
1548 ) -> Option<ErrorGuaranteed> {
1549 if diagnostic.has_future_breakage() {
1550 assert_matches!(diagnostic.level, Error | ForceWarning | Warning | Allow | Expect);
1554 self.future_breakage_diagnostics.push(diagnostic.clone());
1555 }
1556
1557 match diagnostic.level {
1561 Bug => {}
1562 Fatal | Error => {
1563 if self.treat_next_err_as_bug() {
1564 diagnostic.level = Bug;
1566 }
1567 }
1568 DelayedBug => {
1569 if self.flags.eagerly_emit_delayed_bugs {
1574 if self.treat_next_err_as_bug() {
1576 diagnostic.level = Bug;
1577 } else {
1578 diagnostic.level = Error;
1579 }
1580 } else {
1581 return if let Some(guar) = self.has_errors() {
1584 Some(guar)
1585 } else {
1586 let backtrace = std::backtrace::Backtrace::capture();
1590 #[allow(deprecated)]
1594 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1595 self.delayed_bugs
1596 .push((DelayedDiagInner::with_backtrace(diagnostic, backtrace), guar));
1597 Some(guar)
1598 };
1599 }
1600 }
1601 ForceWarning if diagnostic.lint_id.is_none() => {} Warning => {
1603 if !self.flags.can_emit_warnings {
1604 if diagnostic.has_future_breakage() {
1606 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1608 }
1609 return None;
1610 }
1611 }
1612 Note | Help | FailureNote => {}
1613 OnceNote | OnceHelp => panic!("bad level: {:?}", diagnostic.level),
1614 Allow => {
1615 if diagnostic.has_future_breakage() {
1617 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1619 self.suppressed_expected_diag = true;
1620 }
1621 return None;
1622 }
1623 Expect | ForceWarning => {
1624 self.fulfilled_expectations.insert(diagnostic.lint_id.unwrap());
1625 if let Expect = diagnostic.level {
1626 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1628 self.suppressed_expected_diag = true;
1629 return None;
1630 }
1631 }
1632 }
1633
1634 TRACK_DIAGNOSTIC(diagnostic, &mut |mut diagnostic| {
1635 if let Some(code) = diagnostic.code {
1636 self.emitted_diagnostic_codes.insert(code);
1637 }
1638
1639 let already_emitted = {
1640 let mut hasher = StableHasher::new();
1641 diagnostic.hash(&mut hasher);
1642 let diagnostic_hash = hasher.finish();
1643 !self.emitted_diagnostics.insert(diagnostic_hash)
1644 };
1645
1646 let is_error = diagnostic.is_error();
1647 let is_lint = diagnostic.is_lint.is_some();
1648
1649 if !(self.flags.deduplicate_diagnostics && already_emitted) {
1652 debug!(?diagnostic);
1653 debug!(?self.emitted_diagnostics);
1654
1655 let not_yet_emitted = |sub: &mut Subdiag| {
1656 debug!(?sub);
1657 if sub.level != OnceNote && sub.level != OnceHelp {
1658 return true;
1659 }
1660 let mut hasher = StableHasher::new();
1661 sub.hash(&mut hasher);
1662 let diagnostic_hash = hasher.finish();
1663 debug!(?diagnostic_hash);
1664 self.emitted_diagnostics.insert(diagnostic_hash)
1665 };
1666 diagnostic.children.retain_mut(not_yet_emitted);
1667 if already_emitted {
1668 let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`";
1669 diagnostic.sub(Note, msg, MultiSpan::new());
1670 }
1671
1672 if is_error {
1673 self.deduplicated_err_count += 1;
1674 } else if matches!(diagnostic.level, ForceWarning | Warning) {
1675 self.deduplicated_warn_count += 1;
1676 }
1677 self.has_printed = true;
1678
1679 self.emitter.emit_diagnostic(diagnostic, &self.registry);
1680 }
1681
1682 if is_error {
1683 if !self.delayed_bugs.is_empty() {
1688 assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0);
1689 self.delayed_bugs.clear();
1690 self.delayed_bugs.shrink_to_fit();
1691 }
1692
1693 #[allow(deprecated)]
1696 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1697 if is_lint {
1698 self.lint_err_guars.push(guar);
1699 } else {
1700 if let Some(taint) = taint {
1701 taint.set(Some(guar));
1702 }
1703 self.err_guars.push(guar);
1704 }
1705 self.panic_if_treat_err_as_bug();
1706 Some(guar)
1707 } else {
1708 None
1709 }
1710 })
1711 }
1712
1713 fn treat_err_as_bug(&self) -> bool {
1714 self.flags
1715 .treat_err_as_bug
1716 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
1717 }
1718
1719 fn treat_next_err_as_bug(&self) -> bool {
1721 self.flags
1722 .treat_err_as_bug
1723 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
1724 }
1725
1726 fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1727 self.err_guars.get(0).copied().or_else(|| {
1728 if let Some((_diag, guar)) = self
1729 .stashed_diagnostics
1730 .values()
1731 .flat_map(|stashed_diagnostics| stashed_diagnostics.values())
1732 .find(|(diag, guar)| guar.is_some() && diag.is_lint.is_none())
1733 {
1734 *guar
1735 } else {
1736 None
1737 }
1738 })
1739 }
1740
1741 fn has_errors(&self) -> Option<ErrorGuaranteed> {
1742 self.err_guars.get(0).copied().or_else(|| self.lint_err_guars.get(0).copied()).or_else(
1743 || {
1744 self.stashed_diagnostics.values().find_map(|stashed_diagnostics| {
1745 stashed_diagnostics.values().find_map(|(_, guar)| *guar)
1746 })
1747 },
1748 )
1749 }
1750
1751 fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1752 self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
1753 }
1754
1755 fn eagerly_translate<'a>(
1757 &self,
1758 message: DiagMessage,
1759 args: impl Iterator<Item = DiagArg<'a>>,
1760 ) -> SubdiagMessage {
1761 SubdiagMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
1762 }
1763
1764 fn eagerly_translate_to_string<'a>(
1766 &self,
1767 message: DiagMessage,
1768 args: impl Iterator<Item = DiagArg<'a>>,
1769 ) -> String {
1770 let args = crate::translation::to_fluent_args(args);
1771 self.emitter
1772 .translator()
1773 .translate_message(&message, &args)
1774 .map_err(Report::new)
1775 .unwrap()
1776 .to_string()
1777 }
1778
1779 fn eagerly_translate_for_subdiag(
1780 &self,
1781 diag: &DiagInner,
1782 msg: impl Into<SubdiagMessage>,
1783 ) -> SubdiagMessage {
1784 let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
1785 self.eagerly_translate(msg, diag.args.iter())
1786 }
1787
1788 fn flush_delayed(&mut self) {
1789 assert!(self.stashed_diagnostics.is_empty());
1793
1794 if !self.err_guars.is_empty() {
1795 return;
1797 }
1798
1799 if self.delayed_bugs.is_empty() {
1800 return;
1802 }
1803
1804 let bugs: Vec<_> =
1805 std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
1806
1807 let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0"));
1808 let decorate = backtrace || self.ice_file.is_none();
1809 let mut out = self
1810 .ice_file
1811 .as_ref()
1812 .and_then(|file| std::fs::File::options().create(true).append(true).open(file).ok());
1813
1814 let note1 = "no errors encountered even though delayed bugs were created";
1819 let note2 = "those delayed bugs will now be shown as internal compiler errors";
1820 self.emit_diagnostic(DiagInner::new(Note, note1), None);
1821 self.emit_diagnostic(DiagInner::new(Note, note2), None);
1822
1823 for bug in bugs {
1824 if let Some(out) = &mut out {
1825 _ = write!(
1826 out,
1827 "delayed bug: {}\n{}\n",
1828 bug.inner
1829 .messages
1830 .iter()
1831 .filter_map(|(msg, _)| msg.as_str())
1832 .collect::<String>(),
1833 &bug.note
1834 );
1835 }
1836
1837 let mut bug = if decorate { bug.decorate(self) } else { bug.inner };
1838
1839 if bug.level != DelayedBug {
1841 bug.arg("level", bug.level);
1848 let msg = crate::fluent_generated::errors_invalid_flushed_delayed_diagnostic_level;
1849 let msg = self.eagerly_translate_for_subdiag(&bug, msg); bug.sub(Note, msg, bug.span.primary_span().unwrap().into());
1851 }
1852 bug.level = Bug;
1853
1854 self.emit_diagnostic(bug, None);
1855 }
1856
1857 panic::panic_any(DelayedBugPanic);
1859 }
1860
1861 fn panic_if_treat_err_as_bug(&self) {
1862 if self.treat_err_as_bug() {
1863 let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
1864 assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
1865 if n == 1 {
1866 panic!("aborting due to `-Z treat-err-as-bug=1`");
1867 } else {
1868 panic!("aborting after {n} errors due to `-Z treat-err-as-bug={n}`");
1869 }
1870 }
1871 }
1872}
1873
1874struct DelayedDiagInner {
1875 inner: DiagInner,
1876 note: Backtrace,
1877}
1878
1879impl DelayedDiagInner {
1880 fn with_backtrace(diagnostic: DiagInner, backtrace: Backtrace) -> Self {
1881 DelayedDiagInner { inner: diagnostic, note: backtrace }
1882 }
1883
1884 fn decorate(self, dcx: &DiagCtxtInner) -> DiagInner {
1885 let mut diag = self.inner;
1889 let msg = match self.note.status() {
1890 BacktraceStatus::Captured => crate::fluent_generated::errors_delayed_at_with_newline,
1891 _ => crate::fluent_generated::errors_delayed_at_without_newline,
1894 };
1895 diag.arg("emitted_at", diag.emitted_at.clone());
1896 diag.arg("note", self.note);
1897 let msg = dcx.eagerly_translate_for_subdiag(&diag, msg); diag.sub(Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into());
1899 diag
1900 }
1901}
1902
1903#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
1923pub enum Level {
1924 Bug,
1926
1927 Fatal,
1930
1931 Error,
1934
1935 DelayedBug,
1940
1941 ForceWarning,
1947
1948 Warning,
1951
1952 Note,
1954
1955 OnceNote,
1957
1958 Help,
1960
1961 OnceHelp,
1963
1964 FailureNote,
1967
1968 Allow,
1970
1971 Expect,
1973}
1974
1975impl fmt::Display for Level {
1976 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1977 self.to_str().fmt(f)
1978 }
1979}
1980
1981impl Level {
1982 fn color(self) -> anstyle::Style {
1983 match self {
1984 Bug | Fatal | Error | DelayedBug => AnsiColor::BrightRed.on_default(),
1985 ForceWarning | Warning => {
1986 if cfg!(windows) {
1987 AnsiColor::BrightYellow.on_default()
1988 } else {
1989 AnsiColor::Yellow.on_default()
1990 }
1991 }
1992 Note | OnceNote => AnsiColor::BrightGreen.on_default(),
1993 Help | OnceHelp => AnsiColor::BrightCyan.on_default(),
1994 FailureNote => anstyle::Style::new(),
1995 Allow | Expect => unreachable!(),
1996 }
1997 }
1998
1999 pub fn to_str(self) -> &'static str {
2000 match self {
2001 Bug | DelayedBug => "error: internal compiler error",
2002 Fatal | Error => "error",
2003 ForceWarning | Warning => "warning",
2004 Note | OnceNote => "note",
2005 Help | OnceHelp => "help",
2006 FailureNote => "failure-note",
2007 Allow | Expect => unreachable!(),
2008 }
2009 }
2010
2011 pub fn is_failure_note(&self) -> bool {
2012 matches!(*self, FailureNote)
2013 }
2014
2015 fn can_be_subdiag(&self) -> bool {
2017 match self {
2018 Bug | DelayedBug | Fatal | Error | ForceWarning | FailureNote | Allow | Expect => false,
2019
2020 Warning | Note | Help | OnceNote | OnceHelp => true,
2021 }
2022 }
2023}
2024
2025impl IntoDiagArg for Level {
2026 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
2027 DiagArgValue::Str(Cow::from(self.to_string()))
2028 }
2029}
2030
2031pub fn elided_lifetime_in_path_suggestion(
2033 source_map: &SourceMap,
2034 n: usize,
2035 path_span: Span,
2036 incl_angl_brckt: bool,
2037 insertion_span: Span,
2038) -> ElidedLifetimeInPathSubdiag {
2039 let expected = ExpectedLifetimeParameter { span: path_span, count: n };
2040 let indicate = source_map.is_span_accessible(insertion_span).then(|| {
2042 let anon_lts = vec!["'_"; n].join(", ");
2043 let suggestion =
2044 if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
2045
2046 IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
2047 });
2048
2049 ElidedLifetimeInPathSubdiag { expected, indicate }
2050}
2051
2052pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
2053 diag: &mut Diag<'a, G>,
2054 ambiguity: rustc_lint_defs::AmbiguityErrorDiag,
2055) {
2056 diag.span_label(ambiguity.label_span, ambiguity.label_msg);
2057 diag.note(ambiguity.note_msg);
2058 diag.span_note(ambiguity.b1_span, ambiguity.b1_note_msg);
2059 for help_msg in ambiguity.b1_help_msgs {
2060 diag.help(help_msg);
2061 }
2062 diag.span_note(ambiguity.b2_span, ambiguity.b2_note_msg);
2063 for help_msg in ambiguity.b2_help_msgs {
2064 diag.help(help_msg);
2065 }
2066}
2067
2068pub fn a_or_an(s: &str) -> &'static str {
2072 let mut chars = s.chars();
2073 let Some(mut first_alpha_char) = chars.next() else {
2074 return "a";
2075 };
2076 if first_alpha_char == '`' {
2077 let Some(next) = chars.next() else {
2078 return "a";
2079 };
2080 first_alpha_char = next;
2081 }
2082 if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
2083 "an"
2084 } else {
2085 "a"
2086 }
2087}
2088
2089#[derive(Clone, Copy, PartialEq, Hash, Debug)]
2090pub enum TerminalUrl {
2091 No,
2092 Yes,
2093 Auto,
2094}