1#![allow(internal_features)]
7#![allow(rustc::diagnostic_outside_of_impl)]
8#![allow(rustc::direct_use_of_rustc_type_ir)]
9#![allow(rustc::untranslatable_diagnostic)]
10#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
11#![doc(rust_logo)]
12#![feature(array_windows)]
13#![feature(assert_matches)]
14#![feature(associated_type_defaults)]
15#![feature(box_patterns)]
16#![feature(default_field_values)]
17#![feature(error_reporter)]
18#![feature(negative_impls)]
19#![feature(never_type)]
20#![feature(rustc_attrs)]
21#![feature(rustdoc_internals)]
22#![feature(try_blocks)]
23#![feature(yeet_expr)]
24extern crate self as rustc_errors;
27
28use std::assert_matches::assert_matches;
29use std::backtrace::{Backtrace, BacktraceStatus};
30use std::borrow::Cow;
31use std::cell::Cell;
32use std::error::Report;
33use std::ffi::OsStr;
34use std::hash::Hash;
35use std::io::Write;
36use std::num::NonZero;
37use std::ops::DerefMut;
38use std::path::{Path, PathBuf};
39use std::{fmt, panic};
40
41use Level::*;
42pub use anstream::{AutoStream, ColorChoice};
45pub use anstyle::{
46 Ansi256Color, AnsiColor, Color, EffectIter, Effects, Reset, RgbColor, Style as Anstyle,
47};
48pub use codes::*;
49pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
50pub use diagnostic::{
51 BugAbort, Diag, DiagArgMap, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee,
52 FatalAbort, LintDiagnostic, LintDiagnosticBox, StringPart, Subdiag, Subdiagnostic,
53};
54pub use diagnostic_impls::{
55 DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
56 IndicateAnonymousLifetime, SingleLabelManySpans,
57};
58pub use emitter::ColorConfig;
59use emitter::{ConfusionType, DynEmitter, Emitter, detect_confusion_type, is_different};
60use rustc_data_structures::AtomicRef;
61use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
62use rustc_data_structures::stable_hasher::StableHasher;
63use rustc_data_structures::sync::{DynSend, Lock};
64pub use rustc_error_messages::{
65 DiagArg, DiagArgFromDisplay, DiagArgName, DiagArgValue, DiagMessage, FluentBundle, IntoDiagArg,
66 LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage,
67 fallback_fluent_bundle, fluent_bundle, into_diag_arg_using_display,
68};
69use rustc_hashes::Hash128;
70pub use rustc_lint_defs::{Applicability, listify, pluralize};
71use rustc_lint_defs::{Lint, LintExpectationId};
72use rustc_macros::{Decodable, Encodable};
73pub use rustc_span::ErrorGuaranteed;
74pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
75use rustc_span::source_map::SourceMap;
76use rustc_span::{BytePos, DUMMY_SP, Loc, Span};
77pub use snippet::Style;
78use tracing::debug;
79
80use crate::emitter::TimingEvent;
81use crate::registry::Registry;
82use crate::timings::TimingRecord;
83
84pub mod annotate_snippet_emitter_writer;
85pub mod codes;
86mod decorate_diag;
87mod diagnostic;
88mod diagnostic_impls;
89pub mod emitter;
90pub mod error;
91pub mod json;
92mod lock;
93pub mod markdown;
94pub mod registry;
95mod snippet;
96mod styled_buffer;
97#[cfg(test)]
98mod tests;
99pub mod timings;
100pub mod translation;
101
102pub type PResult<'a, T> = Result<T, Diag<'a>>;
103
104rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
105
106#[cfg(target_pointer_width = "64")]
108rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24);
109#[cfg(target_pointer_width = "64")]
110rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24);
111
112pub trait LintEmitter: Copy {
115 type Id: Copy;
116 #[track_caller]
117 fn emit_node_span_lint(
118 self,
119 lint: &'static Lint,
120 hir_id: Self::Id,
121 span: impl Into<MultiSpan>,
122 decorator: impl for<'a> LintDiagnostic<'a, ()> + DynSend + 'static,
123 );
124}
125
126#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
127pub enum SuggestionStyle {
128 HideCodeInline,
130 HideCodeAlways,
132 CompletelyHidden,
134 ShowCode,
138 ShowAlways,
140}
141
142impl SuggestionStyle {
143 fn hide_inline(&self) -> bool {
144 !matches!(*self, SuggestionStyle::ShowCode)
145 }
146}
147
148#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
150pub enum Suggestions {
151 Enabled(Vec<CodeSuggestion>),
156 Sealed(Box<[CodeSuggestion]>),
160 Disabled,
164}
165
166impl Suggestions {
167 pub fn unwrap_tag(self) -> Vec<CodeSuggestion> {
169 match self {
170 Suggestions::Enabled(suggestions) => suggestions,
171 Suggestions::Sealed(suggestions) => suggestions.into_vec(),
172 Suggestions::Disabled => Vec::new(),
173 }
174 }
175}
176
177impl Default for Suggestions {
178 fn default() -> Self {
179 Self::Enabled(vec![])
180 }
181}
182
183#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
184pub struct CodeSuggestion {
185 pub substitutions: Vec<Substitution>,
207 pub msg: DiagMessage,
208 pub style: SuggestionStyle,
210 pub applicability: Applicability,
216}
217
218#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
219pub struct Substitution {
221 pub parts: Vec<SubstitutionPart>,
222}
223
224#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
225pub struct SubstitutionPart {
226 pub span: Span,
227 pub snippet: String,
228}
229
230#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
231pub struct TrimmedSubstitutionPart {
232 pub original_span: Span,
233 pub span: Span,
234 pub snippet: String,
235}
236
237#[derive(Debug, Clone, Copy)]
240pub(crate) struct SubstitutionHighlight {
241 start: usize,
242 end: usize,
243}
244
245impl SubstitutionPart {
246 fn trim_trivial_replacements(self, sm: &SourceMap) -> TrimmedSubstitutionPart {
249 let mut trimmed_part = TrimmedSubstitutionPart {
250 original_span: self.span,
251 span: self.span,
252 snippet: self.snippet,
253 };
254 if trimmed_part.snippet.is_empty() {
255 return trimmed_part;
256 }
257 let Ok(snippet) = sm.span_to_snippet(trimmed_part.span) else {
258 return trimmed_part;
259 };
260
261 if let Some((prefix, substr, suffix)) = as_substr(&snippet, &trimmed_part.snippet) {
262 trimmed_part.span = Span::new(
263 trimmed_part.span.lo() + BytePos(prefix as u32),
264 trimmed_part.span.hi() - BytePos(suffix as u32),
265 trimmed_part.span.ctxt(),
266 trimmed_part.span.parent(),
267 );
268 trimmed_part.snippet = substr.to_string();
269 }
270 trimmed_part
271 }
272}
273
274impl TrimmedSubstitutionPart {
275 pub fn is_addition(&self, sm: &SourceMap) -> bool {
276 !self.snippet.is_empty() && !self.replaces_meaningful_content(sm)
277 }
278
279 pub fn is_deletion(&self, sm: &SourceMap) -> bool {
280 self.snippet.trim().is_empty() && self.replaces_meaningful_content(sm)
281 }
282
283 pub fn is_replacement(&self, sm: &SourceMap) -> bool {
284 !self.snippet.is_empty() && self.replaces_meaningful_content(sm)
285 }
286
287 pub fn is_destructive_replacement(&self, sm: &SourceMap) -> bool {
292 self.is_replacement(sm)
293 && !sm
294 .span_to_snippet(self.span)
295 .is_ok_and(|snippet| as_substr(snippet.trim(), self.snippet.trim()).is_some())
296 }
297
298 fn replaces_meaningful_content(&self, sm: &SourceMap) -> bool {
299 sm.span_to_snippet(self.span)
300 .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty())
301 }
302}
303
304fn as_substr<'a>(original: &'a str, suggestion: &'a str) -> Option<(usize, &'a str, usize)> {
309 let common_prefix = original
310 .chars()
311 .zip(suggestion.chars())
312 .take_while(|(c1, c2)| c1 == c2)
313 .map(|(c, _)| c.len_utf8())
314 .sum();
315 let original = &original[common_prefix..];
316 let suggestion = &suggestion[common_prefix..];
317 if suggestion.ends_with(original) {
318 let common_suffix = original.len();
319 Some((common_prefix, &suggestion[..suggestion.len() - original.len()], common_suffix))
320 } else {
321 None
322 }
323}
324
325impl CodeSuggestion {
326 pub(crate) fn splice_lines(
329 &self,
330 sm: &SourceMap,
331 ) -> Vec<(String, Vec<TrimmedSubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, ConfusionType)>
332 {
333 use rustc_span::{CharPos, Pos};
338
339 fn push_trailing(
348 buf: &mut String,
349 line_opt: Option<&Cow<'_, str>>,
350 lo: &Loc,
351 hi_opt: Option<&Loc>,
352 ) -> usize {
353 let mut line_count = 0;
354 let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
357 if let Some(line) = line_opt {
358 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
359 let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
361 match hi_opt {
362 Some(hi) if hi > lo => {
364 line_count = line[lo..hi].matches('\n').count();
366 buf.push_str(&line[lo..hi])
367 }
368 Some(_) => (),
369 None => {
371 line_count = line[lo..].matches('\n').count();
373 buf.push_str(&line[lo..])
374 }
375 }
376 }
377 if hi_opt.is_none() {
379 buf.push('\n');
380 }
381 }
382 line_count
383 }
384
385 assert!(!self.substitutions.is_empty());
386
387 self.substitutions
388 .iter()
389 .filter(|subst| {
390 let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
393 if invalid {
394 debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
395 }
396 !invalid
397 })
398 .cloned()
399 .filter_map(|mut substitution| {
400 substitution.parts.sort_by_key(|part| part.span.lo());
403
404 let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
406 let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
407 let bounding_span = Span::with_root_ctxt(lo, hi);
408 let lines = sm.span_to_lines(bounding_span).ok()?;
410 assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
411
412 if !sm.ensure_source_file_source_present(&lines.file) {
414 return None;
415 }
416
417 let mut highlights = vec![];
418 let sf = &lines.file;
428 let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
429 prev_hi.col = CharPos::from_usize(0);
430 let mut prev_line =
431 lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
432 let mut buf = String::new();
433
434 let mut line_highlight = vec![];
435 let mut acc = 0;
438 let mut confusion_type = ConfusionType::None;
439
440 let trimmed_parts = substitution
441 .parts
442 .into_iter()
443 .map(|part| part.trim_trivial_replacements(sm))
447 .collect::<Vec<_>>();
448
449 for part in &trimmed_parts {
450 let part_confusion = detect_confusion_type(sm, &part.snippet, part.span);
451 confusion_type = confusion_type.combine(part_confusion);
452 let cur_lo = sm.lookup_char_pos(part.span.lo());
453 if prev_hi.line == cur_lo.line {
454 let mut count =
455 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
456 while count > 0 {
457 highlights.push(std::mem::take(&mut line_highlight));
458 acc = 0;
459 count -= 1;
460 }
461 } else {
462 acc = 0;
463 highlights.push(std::mem::take(&mut line_highlight));
464 let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
465 while count > 0 {
466 highlights.push(std::mem::take(&mut line_highlight));
467 count -= 1;
468 }
469 for idx in prev_hi.line..(cur_lo.line - 1) {
471 if let Some(line) = sf.get_line(idx) {
472 buf.push_str(line.as_ref());
473 buf.push('\n');
474 highlights.push(std::mem::take(&mut line_highlight));
475 }
476 }
477 if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
478 let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
479 Some((i, _)) => i,
480 None => cur_line.len(),
481 };
482 buf.push_str(&cur_line[..end]);
483 }
484 }
485 let len: isize = part
487 .snippet
488 .split('\n')
489 .next()
490 .unwrap_or(&part.snippet)
491 .chars()
492 .map(|c| match c {
493 '\t' => 4,
494 _ => 1,
495 })
496 .sum();
497 if !is_different(sm, &part.snippet, part.span) {
498 } else {
502 line_highlight.push(SubstitutionHighlight {
503 start: (cur_lo.col.0 as isize + acc) as usize,
504 end: (cur_lo.col.0 as isize + acc + len) as usize,
505 });
506 }
507 buf.push_str(&part.snippet);
508 let cur_hi = sm.lookup_char_pos(part.span.hi());
509 acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
514 prev_hi = cur_hi;
515 prev_line = sf.get_line(prev_hi.line - 1);
516 for line in part.snippet.split('\n').skip(1) {
517 acc = 0;
518 highlights.push(std::mem::take(&mut line_highlight));
519 let end: usize = line
520 .chars()
521 .map(|c| match c {
522 '\t' => 4,
523 _ => 1,
524 })
525 .sum();
526 line_highlight.push(SubstitutionHighlight { start: 0, end });
527 }
528 }
529 highlights.push(std::mem::take(&mut line_highlight));
530 if !buf.ends_with('\n') {
532 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
533 }
534 while buf.ends_with('\n') {
536 buf.pop();
537 }
538 if highlights.iter().all(|parts| parts.is_empty()) {
539 None
540 } else {
541 Some((buf, trimmed_parts, highlights, confusion_type))
542 }
543 })
544 .collect()
545 }
546}
547
548pub struct ExplicitBug;
551
552pub struct DelayedBugPanic;
555
556pub struct DiagCtxt {
560 inner: Lock<DiagCtxtInner>,
561}
562
563#[derive(Copy, Clone)]
564pub struct DiagCtxtHandle<'a> {
565 dcx: &'a DiagCtxt,
566 tainted_with_errors: Option<&'a Cell<Option<ErrorGuaranteed>>>,
569}
570
571impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
572 type Target = &'a DiagCtxt;
573
574 fn deref(&self) -> &Self::Target {
575 &self.dcx
576 }
577}
578
579struct DiagCtxtInner {
583 flags: DiagCtxtFlags,
584
585 registry: Registry,
586
587 err_guars: Vec<ErrorGuaranteed>,
589 lint_err_guars: Vec<ErrorGuaranteed>,
592 delayed_bugs: Vec<(DelayedDiagInner, ErrorGuaranteed)>,
594
595 deduplicated_err_count: usize,
597 deduplicated_warn_count: usize,
599
600 emitter: Box<DynEmitter>,
601
602 must_produce_diag: Option<Backtrace>,
605
606 has_printed: bool,
609
610 suppressed_expected_diag: bool,
613
614 taught_diagnostics: FxHashSet<ErrCode>,
618
619 emitted_diagnostic_codes: FxIndexSet<ErrCode>,
621
622 emitted_diagnostics: FxHashSet<Hash128>,
626
627 stashed_diagnostics:
633 FxIndexMap<StashKey, FxIndexMap<Span, (DiagInner, Option<ErrorGuaranteed>)>>,
634
635 future_breakage_diagnostics: Vec<DiagInner>,
636
637 fulfilled_expectations: FxIndexSet<LintExpectationId>,
649
650 ice_file: Option<PathBuf>,
653}
654
655#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
657pub enum StashKey {
658 ItemNoType,
659 UnderscoreForArrayLengths,
660 EarlySyntaxWarning,
661 CallIntoMethod,
662 LifetimeIsChar,
665 MaybeFruTypo,
668 CallAssocMethod,
669 AssociatedTypeSuggestion,
670 Cycle,
672 UndeterminedMacroResolution,
673 ExprInPat,
675 GenericInFieldExpr,
679}
680
681fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
682 (*f)(diag)
683}
684
685pub static TRACK_DIAGNOSTIC: AtomicRef<
688 fn(DiagInner, &mut dyn FnMut(DiagInner) -> Option<ErrorGuaranteed>) -> Option<ErrorGuaranteed>,
689> = AtomicRef::new(&(default_track_diagnostic as _));
690
691#[derive(Copy, Clone, Default)]
692pub struct DiagCtxtFlags {
693 pub can_emit_warnings: bool,
696 pub treat_err_as_bug: Option<NonZero<usize>>,
699 pub eagerly_emit_delayed_bugs: bool,
702 pub macro_backtrace: bool,
705 pub deduplicate_diagnostics: bool,
707 pub track_diagnostics: bool,
709}
710
711impl Drop for DiagCtxtInner {
712 fn drop(&mut self) {
713 self.emit_stashed_diagnostics();
721
722 self.flush_delayed();
726
727 if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
731 if let Some(backtrace) = &self.must_produce_diag {
732 let suggestion = match backtrace.status() {
733 BacktraceStatus::Disabled => String::from(
734 "Backtraces are currently disabled: set `RUST_BACKTRACE=1` and re-run \
735 to see where it happened.",
736 ),
737 BacktraceStatus::Captured => format!(
738 "This happened in the following `must_produce_diag` call's backtrace:\n\
739 {backtrace}",
740 ),
741 _ => String::from("(impossible to capture backtrace where this happened)"),
742 };
743 panic!(
744 "`trimmed_def_paths` called, diagnostics were expected but none were emitted. \
745 Use `with_no_trimmed_paths` for debugging. {suggestion}"
746 );
747 }
748 }
749 }
750}
751
752impl DiagCtxt {
753 pub fn disable_warnings(mut self) -> Self {
754 self.inner.get_mut().flags.can_emit_warnings = false;
755 self
756 }
757
758 pub fn with_flags(mut self, flags: DiagCtxtFlags) -> Self {
759 self.inner.get_mut().flags = flags;
760 self
761 }
762
763 pub fn with_ice_file(mut self, ice_file: PathBuf) -> Self {
764 self.inner.get_mut().ice_file = Some(ice_file);
765 self
766 }
767
768 pub fn with_registry(mut self, registry: Registry) -> Self {
769 self.inner.get_mut().registry = registry;
770 self
771 }
772
773 pub fn new(emitter: Box<DynEmitter>) -> Self {
774 Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
775 }
776
777 pub fn make_silent(&self) {
778 let mut inner = self.inner.borrow_mut();
779 let translator = inner.emitter.translator().clone();
780 inner.emitter = Box::new(emitter::SilentEmitter { translator });
781 }
782
783 pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) {
784 self.inner.borrow_mut().emitter = emitter;
785 }
786
787 pub fn eagerly_translate<'a>(
789 &self,
790 message: DiagMessage,
791 args: impl Iterator<Item = DiagArg<'a>>,
792 ) -> SubdiagMessage {
793 let inner = self.inner.borrow();
794 inner.eagerly_translate(message, args)
795 }
796
797 pub fn eagerly_translate_to_string<'a>(
799 &self,
800 message: DiagMessage,
801 args: impl Iterator<Item = DiagArg<'a>>,
802 ) -> String {
803 let inner = self.inner.borrow();
804 inner.eagerly_translate_to_string(message, args)
805 }
806
807 pub fn can_emit_warnings(&self) -> bool {
811 self.inner.borrow_mut().flags.can_emit_warnings
812 }
813
814 pub fn reset_err_count(&self) {
820 let mut inner = self.inner.borrow_mut();
823 let DiagCtxtInner {
824 flags: _,
825 registry: _,
826 err_guars,
827 lint_err_guars,
828 delayed_bugs,
829 deduplicated_err_count,
830 deduplicated_warn_count,
831 emitter: _,
832 must_produce_diag,
833 has_printed,
834 suppressed_expected_diag,
835 taught_diagnostics,
836 emitted_diagnostic_codes,
837 emitted_diagnostics,
838 stashed_diagnostics,
839 future_breakage_diagnostics,
840 fulfilled_expectations,
841 ice_file: _,
842 } = inner.deref_mut();
843
844 *err_guars = Default::default();
847 *lint_err_guars = Default::default();
848 *delayed_bugs = Default::default();
849 *deduplicated_err_count = 0;
850 *deduplicated_warn_count = 0;
851 *must_produce_diag = None;
852 *has_printed = false;
853 *suppressed_expected_diag = false;
854 *taught_diagnostics = Default::default();
855 *emitted_diagnostic_codes = Default::default();
856 *emitted_diagnostics = Default::default();
857 *stashed_diagnostics = Default::default();
858 *future_breakage_diagnostics = Default::default();
859 *fulfilled_expectations = Default::default();
860 }
861
862 pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> {
863 DiagCtxtHandle { dcx: self, tainted_with_errors: None }
864 }
865
866 pub fn taintable_handle<'a>(
870 &'a self,
871 tainted_with_errors: &'a Cell<Option<ErrorGuaranteed>>,
872 ) -> DiagCtxtHandle<'a> {
873 DiagCtxtHandle { dcx: self, tainted_with_errors: Some(tainted_with_errors) }
874 }
875}
876
877impl<'a> DiagCtxtHandle<'a> {
878 pub fn stash_diagnostic(
900 &self,
901 span: Span,
902 key: StashKey,
903 diag: DiagInner,
904 ) -> Option<ErrorGuaranteed> {
905 let guar = match diag.level {
906 Bug | Fatal => {
907 self.span_bug(
908 span,
909 format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
910 );
911 }
912 Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
916 DelayedBug => {
917 return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors);
918 }
919 ForceWarning | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
920 | Expect => None,
921 };
922
923 self.inner
927 .borrow_mut()
928 .stashed_diagnostics
929 .entry(key)
930 .or_default()
931 .insert(span.with_parent(None), (diag, guar));
932
933 guar
934 }
935
936 pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
940 let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
942 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
943 )?;
944 assert!(!diag.is_error());
945 assert!(guar.is_none());
946 Some(Diag::new_diagnostic(self, diag))
947 }
948
949 pub fn try_steal_modify_and_emit_err<F>(
954 self,
955 span: Span,
956 key: StashKey,
957 mut modify_err: F,
958 ) -> Option<ErrorGuaranteed>
959 where
960 F: FnMut(&mut Diag<'_>),
961 {
962 let err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
964 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
965 );
966 err.map(|(err, guar)| {
967 assert_eq!(err.level, Error);
969 assert!(guar.is_some());
970 let mut err = Diag::<ErrorGuaranteed>::new_diagnostic(self, err);
971 modify_err(&mut err);
972 assert_eq!(err.level, Error);
973 err.emit()
974 })
975 }
976
977 pub fn try_steal_replace_and_emit_err(
981 self,
982 span: Span,
983 key: StashKey,
984 new_err: Diag<'_>,
985 ) -> ErrorGuaranteed {
986 let old_err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
988 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
989 );
990 match old_err {
991 Some((old_err, guar)) => {
992 assert_eq!(old_err.level, Error);
993 assert!(guar.is_some());
994 Diag::<ErrorGuaranteed>::new_diagnostic(self, old_err).cancel();
997 }
998 None => {}
999 };
1000 new_err.emit()
1001 }
1002
1003 pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
1004 let inner = self.inner.borrow();
1005 if let Some(stashed_diagnostics) = inner.stashed_diagnostics.get(&key)
1006 && !stashed_diagnostics.is_empty()
1007 {
1008 stashed_diagnostics.contains_key(&span.with_parent(None))
1009 } else {
1010 false
1011 }
1012 }
1013
1014 pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
1016 self.inner.borrow_mut().emit_stashed_diagnostics()
1017 }
1018
1019 #[inline]
1021 pub fn err_count(&self) -> usize {
1022 let inner = self.inner.borrow();
1023 inner.err_guars.len()
1024 + inner.lint_err_guars.len()
1025 + inner
1026 .stashed_diagnostics
1027 .values()
1028 .map(|a| a.values().filter(|(_, guar)| guar.is_some()).count())
1029 .sum::<usize>()
1030 }
1031
1032 pub fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1035 self.inner.borrow().has_errors_excluding_lint_errors()
1036 }
1037
1038 pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
1040 self.inner.borrow().has_errors()
1041 }
1042
1043 pub fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1046 self.inner.borrow().has_errors_or_delayed_bugs()
1047 }
1048
1049 pub fn print_error_count(&self) {
1050 let mut inner = self.inner.borrow_mut();
1051
1052 assert!(inner.stashed_diagnostics.is_empty());
1055
1056 if inner.treat_err_as_bug() {
1057 return;
1058 }
1059
1060 let warnings = match inner.deduplicated_warn_count {
1061 0 => Cow::from(""),
1062 1 => Cow::from("1 warning emitted"),
1063 count => Cow::from(format!("{count} warnings emitted")),
1064 };
1065 let errors = match inner.deduplicated_err_count {
1066 0 => Cow::from(""),
1067 1 => Cow::from("aborting due to 1 previous error"),
1068 count => Cow::from(format!("aborting due to {count} previous errors")),
1069 };
1070
1071 match (errors.len(), warnings.len()) {
1072 (0, 0) => return,
1073 (0, _) => {
1074 inner.emit_diagnostic(
1077 DiagInner::new(ForceWarning, DiagMessage::Str(warnings)),
1078 None,
1079 );
1080 }
1081 (_, 0) => {
1082 inner.emit_diagnostic(DiagInner::new(Error, errors), self.tainted_with_errors);
1083 }
1084 (_, _) => {
1085 inner.emit_diagnostic(
1086 DiagInner::new(Error, format!("{errors}; {warnings}")),
1087 self.tainted_with_errors,
1088 );
1089 }
1090 }
1091
1092 let can_show_explain = inner.emitter.should_show_explain();
1093 let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty();
1094 if can_show_explain && are_there_diagnostics {
1095 let mut error_codes = inner
1096 .emitted_diagnostic_codes
1097 .iter()
1098 .filter_map(|&code| {
1099 if inner.registry.try_find_description(code).is_ok() {
1100 Some(code.to_string())
1101 } else {
1102 None
1103 }
1104 })
1105 .collect::<Vec<_>>();
1106 if !error_codes.is_empty() {
1107 error_codes.sort();
1108 if error_codes.len() > 1 {
1109 let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
1110 let msg1 = format!(
1111 "Some errors have detailed explanations: {}{}",
1112 error_codes[..limit].join(", "),
1113 if error_codes.len() > 9 { "..." } else { "." }
1114 );
1115 let msg2 = format!(
1116 "For more information about an error, try `rustc --explain {}`.",
1117 &error_codes[0]
1118 );
1119 inner.emit_diagnostic(DiagInner::new(FailureNote, msg1), None);
1120 inner.emit_diagnostic(DiagInner::new(FailureNote, msg2), None);
1121 } else {
1122 let msg = format!(
1123 "For more information about this error, try `rustc --explain {}`.",
1124 &error_codes[0]
1125 );
1126 inner.emit_diagnostic(DiagInner::new(FailureNote, msg), None);
1127 }
1128 }
1129 }
1130 }
1131
1132 pub fn abort_if_errors(&self) {
1137 if let Some(guar) = self.has_errors() {
1138 guar.raise_fatal();
1139 }
1140 }
1141
1142 pub fn must_teach(&self, code: ErrCode) -> bool {
1148 self.inner.borrow_mut().taught_diagnostics.insert(code)
1149 }
1150
1151 pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
1152 self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors)
1153 }
1154
1155 pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
1156 self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
1157 }
1158
1159 pub fn emit_timing_section_start(&self, record: TimingRecord) {
1160 self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::Start);
1161 }
1162
1163 pub fn emit_timing_section_end(&self, record: TimingRecord) {
1164 self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::End);
1165 }
1166
1167 pub fn emit_future_breakage_report(&self) {
1168 let inner = &mut *self.inner.borrow_mut();
1169 let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
1170 if !diags.is_empty() {
1171 inner.emitter.emit_future_breakage_report(diags, &inner.registry);
1172 }
1173 }
1174
1175 pub fn emit_unused_externs(
1176 &self,
1177 lint_level: rustc_lint_defs::Level,
1178 loud: bool,
1179 unused_externs: &[&str],
1180 ) {
1181 let mut inner = self.inner.borrow_mut();
1182
1183 if loud && lint_level.is_error() {
1194 #[allow(deprecated)]
1197 inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
1198 inner.panic_if_treat_err_as_bug();
1199 }
1200
1201 inner.emitter.emit_unused_externs(lint_level, unused_externs)
1202 }
1203
1204 #[must_use]
1207 pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
1208 std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
1209 }
1210
1211 pub fn flush_delayed(&self) {
1212 self.inner.borrow_mut().flush_delayed();
1213 }
1214
1215 #[track_caller]
1218 pub fn set_must_produce_diag(&self) {
1219 assert!(
1220 self.inner.borrow().must_produce_diag.is_none(),
1221 "should only need to collect a backtrace once"
1222 );
1223 self.inner.borrow_mut().must_produce_diag = Some(Backtrace::capture());
1224 }
1225}
1226
1227impl<'a> DiagCtxtHandle<'a> {
1232 #[track_caller]
1235 pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> {
1236 Diag::new(self, Bug, msg.into())
1237 }
1238
1239 #[track_caller]
1242 pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
1243 self.struct_bug(msg).emit()
1244 }
1245
1246 #[track_caller]
1249 pub fn struct_span_bug(
1250 self,
1251 span: impl Into<MultiSpan>,
1252 msg: impl Into<Cow<'static, str>>,
1253 ) -> Diag<'a, BugAbort> {
1254 self.struct_bug(msg).with_span(span)
1255 }
1256
1257 #[track_caller]
1260 pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
1261 self.struct_span_bug(span, msg.into()).emit()
1262 }
1263
1264 #[track_caller]
1265 pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> {
1266 bug.into_diag(self, Bug)
1267 }
1268
1269 #[track_caller]
1270 pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! {
1271 self.create_bug(bug).emit()
1272 }
1273
1274 #[rustc_lint_diagnostics]
1275 #[track_caller]
1276 pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> {
1277 Diag::new(self, Fatal, msg)
1278 }
1279
1280 #[rustc_lint_diagnostics]
1281 #[track_caller]
1282 pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
1283 self.struct_fatal(msg).emit()
1284 }
1285
1286 #[rustc_lint_diagnostics]
1287 #[track_caller]
1288 pub fn struct_span_fatal(
1289 self,
1290 span: impl Into<MultiSpan>,
1291 msg: impl Into<DiagMessage>,
1292 ) -> Diag<'a, FatalAbort> {
1293 self.struct_fatal(msg).with_span(span)
1294 }
1295
1296 #[rustc_lint_diagnostics]
1297 #[track_caller]
1298 pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
1299 self.struct_span_fatal(span, msg).emit()
1300 }
1301
1302 #[track_caller]
1303 pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> {
1304 fatal.into_diag(self, Fatal)
1305 }
1306
1307 #[track_caller]
1308 pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
1309 self.create_fatal(fatal).emit()
1310 }
1311
1312 #[track_caller]
1313 pub fn create_almost_fatal(
1314 self,
1315 fatal: impl Diagnostic<'a, FatalError>,
1316 ) -> Diag<'a, FatalError> {
1317 fatal.into_diag(self, Fatal)
1318 }
1319
1320 #[track_caller]
1321 pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError {
1322 self.create_almost_fatal(fatal).emit()
1323 }
1324
1325 #[rustc_lint_diagnostics]
1327 #[track_caller]
1328 pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> {
1329 Diag::new(self, Error, msg)
1330 }
1331
1332 #[rustc_lint_diagnostics]
1333 #[track_caller]
1334 pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
1335 self.struct_err(msg).emit()
1336 }
1337
1338 #[rustc_lint_diagnostics]
1339 #[track_caller]
1340 pub fn struct_span_err(
1341 self,
1342 span: impl Into<MultiSpan>,
1343 msg: impl Into<DiagMessage>,
1344 ) -> Diag<'a> {
1345 self.struct_err(msg).with_span(span)
1346 }
1347
1348 #[rustc_lint_diagnostics]
1349 #[track_caller]
1350 pub fn span_err(
1351 self,
1352 span: impl Into<MultiSpan>,
1353 msg: impl Into<DiagMessage>,
1354 ) -> ErrorGuaranteed {
1355 self.struct_span_err(span, msg).emit()
1356 }
1357
1358 #[track_caller]
1359 pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> {
1360 err.into_diag(self, Error)
1361 }
1362
1363 #[track_caller]
1364 pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
1365 self.create_err(err).emit()
1366 }
1367
1368 #[track_caller]
1373 pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
1374 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
1375 }
1376
1377 #[track_caller]
1385 pub fn span_delayed_bug(
1386 self,
1387 sp: impl Into<MultiSpan>,
1388 msg: impl Into<Cow<'static, str>>,
1389 ) -> ErrorGuaranteed {
1390 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
1391 }
1392
1393 #[rustc_lint_diagnostics]
1394 #[track_caller]
1395 pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1396 Diag::new(self, Warning, msg)
1397 }
1398
1399 #[rustc_lint_diagnostics]
1400 #[track_caller]
1401 pub fn warn(self, msg: impl Into<DiagMessage>) {
1402 self.struct_warn(msg).emit()
1403 }
1404
1405 #[rustc_lint_diagnostics]
1406 #[track_caller]
1407 pub fn struct_span_warn(
1408 self,
1409 span: impl Into<MultiSpan>,
1410 msg: impl Into<DiagMessage>,
1411 ) -> Diag<'a, ()> {
1412 self.struct_warn(msg).with_span(span)
1413 }
1414
1415 #[rustc_lint_diagnostics]
1416 #[track_caller]
1417 pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1418 self.struct_span_warn(span, msg).emit()
1419 }
1420
1421 #[track_caller]
1422 pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1423 warning.into_diag(self, Warning)
1424 }
1425
1426 #[track_caller]
1427 pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) {
1428 self.create_warn(warning).emit()
1429 }
1430
1431 #[rustc_lint_diagnostics]
1432 #[track_caller]
1433 pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1434 Diag::new(self, Note, msg)
1435 }
1436
1437 #[rustc_lint_diagnostics]
1438 #[track_caller]
1439 pub fn note(&self, msg: impl Into<DiagMessage>) {
1440 self.struct_note(msg).emit()
1441 }
1442
1443 #[rustc_lint_diagnostics]
1444 #[track_caller]
1445 pub fn struct_span_note(
1446 self,
1447 span: impl Into<MultiSpan>,
1448 msg: impl Into<DiagMessage>,
1449 ) -> Diag<'a, ()> {
1450 self.struct_note(msg).with_span(span)
1451 }
1452
1453 #[rustc_lint_diagnostics]
1454 #[track_caller]
1455 pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1456 self.struct_span_note(span, msg).emit()
1457 }
1458
1459 #[track_caller]
1460 pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1461 note.into_diag(self, Note)
1462 }
1463
1464 #[track_caller]
1465 pub fn emit_note(self, note: impl Diagnostic<'a, ()>) {
1466 self.create_note(note).emit()
1467 }
1468
1469 #[rustc_lint_diagnostics]
1470 #[track_caller]
1471 pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1472 Diag::new(self, Help, msg)
1473 }
1474
1475 #[rustc_lint_diagnostics]
1476 #[track_caller]
1477 pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1478 Diag::new(self, FailureNote, msg)
1479 }
1480
1481 #[rustc_lint_diagnostics]
1482 #[track_caller]
1483 pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1484 Diag::new(self, Allow, msg)
1485 }
1486
1487 #[rustc_lint_diagnostics]
1488 #[track_caller]
1489 pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> {
1490 Diag::new(self, Expect, msg).with_lint_id(id)
1491 }
1492}
1493
1494impl DiagCtxtInner {
1499 fn new(emitter: Box<DynEmitter>) -> Self {
1500 Self {
1501 flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
1502 registry: Registry::new(&[]),
1503 err_guars: Vec::new(),
1504 lint_err_guars: Vec::new(),
1505 delayed_bugs: Vec::new(),
1506 deduplicated_err_count: 0,
1507 deduplicated_warn_count: 0,
1508 emitter,
1509 must_produce_diag: None,
1510 has_printed: false,
1511 suppressed_expected_diag: false,
1512 taught_diagnostics: Default::default(),
1513 emitted_diagnostic_codes: Default::default(),
1514 emitted_diagnostics: Default::default(),
1515 stashed_diagnostics: Default::default(),
1516 future_breakage_diagnostics: Vec::new(),
1517 fulfilled_expectations: Default::default(),
1518 ice_file: None,
1519 }
1520 }
1521
1522 fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
1524 let mut guar = None;
1525 let has_errors = !self.err_guars.is_empty();
1526 for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
1527 for (_, (diag, _guar)) in stashed_diagnostics {
1528 if !diag.is_error() {
1529 if !diag.is_force_warn() && has_errors {
1533 continue;
1534 }
1535 }
1536 guar = guar.or(self.emit_diagnostic(diag, None));
1537 }
1538 }
1539 guar
1540 }
1541
1542 fn emit_diagnostic(
1544 &mut self,
1545 mut diagnostic: DiagInner,
1546 taint: Option<&Cell<Option<ErrorGuaranteed>>>,
1547 ) -> Option<ErrorGuaranteed> {
1548 if diagnostic.has_future_breakage() {
1549 assert_matches!(diagnostic.level, Error | ForceWarning | Warning | Allow | Expect);
1553 self.future_breakage_diagnostics.push(diagnostic.clone());
1554 }
1555
1556 match diagnostic.level {
1560 Bug => {}
1561 Fatal | Error => {
1562 if self.treat_next_err_as_bug() {
1563 diagnostic.level = Bug;
1565 }
1566 }
1567 DelayedBug => {
1568 if self.flags.eagerly_emit_delayed_bugs {
1573 if self.treat_next_err_as_bug() {
1575 diagnostic.level = Bug;
1576 } else {
1577 diagnostic.level = Error;
1578 }
1579 } else {
1580 return if let Some(guar) = self.has_errors() {
1583 Some(guar)
1584 } else {
1585 let backtrace = std::backtrace::Backtrace::capture();
1589 #[allow(deprecated)]
1593 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1594 self.delayed_bugs
1595 .push((DelayedDiagInner::with_backtrace(diagnostic, backtrace), guar));
1596 Some(guar)
1597 };
1598 }
1599 }
1600 ForceWarning if diagnostic.lint_id.is_none() => {} Warning => {
1602 if !self.flags.can_emit_warnings {
1603 if diagnostic.has_future_breakage() {
1605 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1607 }
1608 return None;
1609 }
1610 }
1611 Note | Help | FailureNote => {}
1612 OnceNote | OnceHelp => panic!("bad level: {:?}", diagnostic.level),
1613 Allow => {
1614 if diagnostic.has_future_breakage() {
1616 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1618 self.suppressed_expected_diag = true;
1619 }
1620 return None;
1621 }
1622 Expect | ForceWarning => {
1623 self.fulfilled_expectations.insert(diagnostic.lint_id.unwrap());
1624 if let Expect = diagnostic.level {
1625 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1627 self.suppressed_expected_diag = true;
1628 return None;
1629 }
1630 }
1631 }
1632
1633 TRACK_DIAGNOSTIC(diagnostic, &mut |mut diagnostic| {
1634 if let Some(code) = diagnostic.code {
1635 self.emitted_diagnostic_codes.insert(code);
1636 }
1637
1638 let already_emitted = {
1639 let mut hasher = StableHasher::new();
1640 diagnostic.hash(&mut hasher);
1641 let diagnostic_hash = hasher.finish();
1642 !self.emitted_diagnostics.insert(diagnostic_hash)
1643 };
1644
1645 let is_error = diagnostic.is_error();
1646 let is_lint = diagnostic.is_lint.is_some();
1647
1648 if !(self.flags.deduplicate_diagnostics && already_emitted) {
1651 debug!(?diagnostic);
1652 debug!(?self.emitted_diagnostics);
1653
1654 let not_yet_emitted = |sub: &mut Subdiag| {
1655 debug!(?sub);
1656 if sub.level != OnceNote && sub.level != OnceHelp {
1657 return true;
1658 }
1659 let mut hasher = StableHasher::new();
1660 sub.hash(&mut hasher);
1661 let diagnostic_hash = hasher.finish();
1662 debug!(?diagnostic_hash);
1663 self.emitted_diagnostics.insert(diagnostic_hash)
1664 };
1665 diagnostic.children.retain_mut(not_yet_emitted);
1666 if already_emitted {
1667 let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`";
1668 diagnostic.sub(Note, msg, MultiSpan::new());
1669 }
1670
1671 if is_error {
1672 self.deduplicated_err_count += 1;
1673 } else if matches!(diagnostic.level, ForceWarning | Warning) {
1674 self.deduplicated_warn_count += 1;
1675 }
1676 self.has_printed = true;
1677
1678 self.emitter.emit_diagnostic(diagnostic, &self.registry);
1679 }
1680
1681 if is_error {
1682 if !self.delayed_bugs.is_empty() {
1687 assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0);
1688 self.delayed_bugs.clear();
1689 self.delayed_bugs.shrink_to_fit();
1690 }
1691
1692 #[allow(deprecated)]
1695 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1696 if is_lint {
1697 self.lint_err_guars.push(guar);
1698 } else {
1699 if let Some(taint) = taint {
1700 taint.set(Some(guar));
1701 }
1702 self.err_guars.push(guar);
1703 }
1704 self.panic_if_treat_err_as_bug();
1705 Some(guar)
1706 } else {
1707 None
1708 }
1709 })
1710 }
1711
1712 fn treat_err_as_bug(&self) -> bool {
1713 self.flags
1714 .treat_err_as_bug
1715 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
1716 }
1717
1718 fn treat_next_err_as_bug(&self) -> bool {
1720 self.flags
1721 .treat_err_as_bug
1722 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
1723 }
1724
1725 fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1726 self.err_guars.get(0).copied().or_else(|| {
1727 if let Some((_diag, guar)) = self
1728 .stashed_diagnostics
1729 .values()
1730 .flat_map(|stashed_diagnostics| stashed_diagnostics.values())
1731 .find(|(diag, guar)| guar.is_some() && diag.is_lint.is_none())
1732 {
1733 *guar
1734 } else {
1735 None
1736 }
1737 })
1738 }
1739
1740 fn has_errors(&self) -> Option<ErrorGuaranteed> {
1741 self.err_guars.get(0).copied().or_else(|| self.lint_err_guars.get(0).copied()).or_else(
1742 || {
1743 self.stashed_diagnostics.values().find_map(|stashed_diagnostics| {
1744 stashed_diagnostics.values().find_map(|(_, guar)| *guar)
1745 })
1746 },
1747 )
1748 }
1749
1750 fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1751 self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
1752 }
1753
1754 fn eagerly_translate<'a>(
1756 &self,
1757 message: DiagMessage,
1758 args: impl Iterator<Item = DiagArg<'a>>,
1759 ) -> SubdiagMessage {
1760 SubdiagMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
1761 }
1762
1763 fn eagerly_translate_to_string<'a>(
1765 &self,
1766 message: DiagMessage,
1767 args: impl Iterator<Item = DiagArg<'a>>,
1768 ) -> String {
1769 let args = crate::translation::to_fluent_args(args);
1770 self.emitter
1771 .translator()
1772 .translate_message(&message, &args)
1773 .map_err(Report::new)
1774 .unwrap()
1775 .to_string()
1776 }
1777
1778 fn eagerly_translate_for_subdiag(
1779 &self,
1780 diag: &DiagInner,
1781 msg: impl Into<SubdiagMessage>,
1782 ) -> SubdiagMessage {
1783 let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
1784 self.eagerly_translate(msg, diag.args.iter())
1785 }
1786
1787 fn flush_delayed(&mut self) {
1788 assert!(self.stashed_diagnostics.is_empty());
1792
1793 if !self.err_guars.is_empty() {
1794 return;
1796 }
1797
1798 if self.delayed_bugs.is_empty() {
1799 return;
1801 }
1802
1803 let bugs: Vec<_> =
1804 std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
1805
1806 let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0"));
1807 let decorate = backtrace || self.ice_file.is_none();
1808 let mut out = self
1809 .ice_file
1810 .as_ref()
1811 .and_then(|file| std::fs::File::options().create(true).append(true).open(file).ok());
1812
1813 let note1 = "no errors encountered even though delayed bugs were created";
1818 let note2 = "those delayed bugs will now be shown as internal compiler errors";
1819 self.emit_diagnostic(DiagInner::new(Note, note1), None);
1820 self.emit_diagnostic(DiagInner::new(Note, note2), None);
1821
1822 for bug in bugs {
1823 if let Some(out) = &mut out {
1824 _ = write!(
1825 out,
1826 "delayed bug: {}\n{}\n",
1827 bug.inner
1828 .messages
1829 .iter()
1830 .filter_map(|(msg, _)| msg.as_str())
1831 .collect::<String>(),
1832 &bug.note
1833 );
1834 }
1835
1836 let mut bug = if decorate { bug.decorate(self) } else { bug.inner };
1837
1838 if bug.level != DelayedBug {
1840 bug.arg("level", bug.level);
1847 let msg = crate::fluent_generated::errors_invalid_flushed_delayed_diagnostic_level;
1848 let msg = self.eagerly_translate_for_subdiag(&bug, msg); bug.sub(Note, msg, bug.span.primary_span().unwrap().into());
1850 }
1851 bug.level = Bug;
1852
1853 self.emit_diagnostic(bug, None);
1854 }
1855
1856 panic::panic_any(DelayedBugPanic);
1858 }
1859
1860 fn panic_if_treat_err_as_bug(&self) {
1861 if self.treat_err_as_bug() {
1862 let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
1863 assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
1864 if n == 1 {
1865 panic!("aborting due to `-Z treat-err-as-bug=1`");
1866 } else {
1867 panic!("aborting after {n} errors due to `-Z treat-err-as-bug={n}`");
1868 }
1869 }
1870 }
1871}
1872
1873struct DelayedDiagInner {
1874 inner: DiagInner,
1875 note: Backtrace,
1876}
1877
1878impl DelayedDiagInner {
1879 fn with_backtrace(diagnostic: DiagInner, backtrace: Backtrace) -> Self {
1880 DelayedDiagInner { inner: diagnostic, note: backtrace }
1881 }
1882
1883 fn decorate(self, dcx: &DiagCtxtInner) -> DiagInner {
1884 let mut diag = self.inner;
1888 let msg = match self.note.status() {
1889 BacktraceStatus::Captured => crate::fluent_generated::errors_delayed_at_with_newline,
1890 _ => crate::fluent_generated::errors_delayed_at_without_newline,
1893 };
1894 diag.arg("emitted_at", diag.emitted_at.clone());
1895 diag.arg("note", self.note);
1896 let msg = dcx.eagerly_translate_for_subdiag(&diag, msg); diag.sub(Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into());
1898 diag
1899 }
1900}
1901
1902#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
1922pub enum Level {
1923 Bug,
1925
1926 Fatal,
1929
1930 Error,
1933
1934 DelayedBug,
1939
1940 ForceWarning,
1946
1947 Warning,
1950
1951 Note,
1953
1954 OnceNote,
1956
1957 Help,
1959
1960 OnceHelp,
1962
1963 FailureNote,
1966
1967 Allow,
1969
1970 Expect,
1972}
1973
1974impl fmt::Display for Level {
1975 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1976 self.to_str().fmt(f)
1977 }
1978}
1979
1980impl Level {
1981 fn color(self) -> anstyle::Style {
1982 match self {
1983 Bug | Fatal | Error | DelayedBug => AnsiColor::BrightRed.on_default(),
1984 ForceWarning | Warning => {
1985 if cfg!(windows) {
1986 AnsiColor::BrightYellow.on_default()
1987 } else {
1988 AnsiColor::Yellow.on_default()
1989 }
1990 }
1991 Note | OnceNote => AnsiColor::BrightGreen.on_default(),
1992 Help | OnceHelp => AnsiColor::BrightCyan.on_default(),
1993 FailureNote => anstyle::Style::new(),
1994 Allow | Expect => unreachable!(),
1995 }
1996 }
1997
1998 pub fn to_str(self) -> &'static str {
1999 match self {
2000 Bug | DelayedBug => "error: internal compiler error",
2001 Fatal | Error => "error",
2002 ForceWarning | Warning => "warning",
2003 Note | OnceNote => "note",
2004 Help | OnceHelp => "help",
2005 FailureNote => "failure-note",
2006 Allow | Expect => unreachable!(),
2007 }
2008 }
2009
2010 pub fn is_failure_note(&self) -> bool {
2011 matches!(*self, FailureNote)
2012 }
2013
2014 fn can_be_subdiag(&self) -> bool {
2016 match self {
2017 Bug | DelayedBug | Fatal | Error | ForceWarning | FailureNote | Allow | Expect => false,
2018
2019 Warning | Note | Help | OnceNote | OnceHelp => true,
2020 }
2021 }
2022}
2023
2024impl IntoDiagArg for Level {
2025 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
2026 DiagArgValue::Str(Cow::from(self.to_string()))
2027 }
2028}
2029
2030pub fn elided_lifetime_in_path_suggestion(
2032 source_map: &SourceMap,
2033 n: usize,
2034 path_span: Span,
2035 incl_angl_brckt: bool,
2036 insertion_span: Span,
2037) -> ElidedLifetimeInPathSubdiag {
2038 let expected = ExpectedLifetimeParameter { span: path_span, count: n };
2039 let indicate = source_map.is_span_accessible(insertion_span).then(|| {
2041 let anon_lts = vec!["'_"; n].join(", ");
2042 let suggestion =
2043 if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
2044
2045 IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
2046 });
2047
2048 ElidedLifetimeInPathSubdiag { expected, indicate }
2049}
2050
2051pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
2052 diag: &mut Diag<'a, G>,
2053 ambiguity: rustc_lint_defs::AmbiguityErrorDiag,
2054) {
2055 diag.span_label(ambiguity.label_span, ambiguity.label_msg);
2056 diag.note(ambiguity.note_msg);
2057 diag.span_note(ambiguity.b1_span, ambiguity.b1_note_msg);
2058 for help_msg in ambiguity.b1_help_msgs {
2059 diag.help(help_msg);
2060 }
2061 diag.span_note(ambiguity.b2_span, ambiguity.b2_note_msg);
2062 for help_msg in ambiguity.b2_help_msgs {
2063 diag.help(help_msg);
2064 }
2065}
2066
2067pub fn a_or_an(s: &str) -> &'static str {
2071 let mut chars = s.chars();
2072 let Some(mut first_alpha_char) = chars.next() else {
2073 return "a";
2074 };
2075 if first_alpha_char == '`' {
2076 let Some(next) = chars.next() else {
2077 return "a";
2078 };
2079 first_alpha_char = next;
2080 }
2081 if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
2082 "an"
2083 } else {
2084 "a"
2085 }
2086}
2087
2088#[derive(Clone, Copy, PartialEq, Hash, Debug)]
2089pub enum TerminalUrl {
2090 No,
2091 Yes,
2092 Auto,
2093}