1#![allow(incomplete_features)]
7#![allow(internal_features)]
8#![allow(rustc::diagnostic_outside_of_impl)]
9#![allow(rustc::untranslatable_diagnostic)]
10#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
11#![doc(rust_logo)]
12#![feature(array_windows)]
13#![feature(assert_matches)]
14#![feature(associated_type_defaults)]
15#![feature(box_patterns)]
16#![feature(default_field_values)]
17#![feature(error_reporter)]
18#![feature(negative_impls)]
19#![feature(never_type)]
20#![feature(rustc_attrs)]
21#![feature(rustdoc_internals)]
22#![feature(try_blocks)]
23#![feature(yeet_expr)]
24extern crate self as rustc_errors;
27
28use std::assert_matches::assert_matches;
29use std::backtrace::{Backtrace, BacktraceStatus};
30use std::borrow::Cow;
31use std::cell::Cell;
32use std::error::Report;
33use std::ffi::OsStr;
34use std::hash::Hash;
35use std::io::Write;
36use std::num::NonZero;
37use std::ops::DerefMut;
38use std::path::{Path, PathBuf};
39use std::{fmt, panic};
40
41use Level::*;
42pub use codes::*;
43pub use diagnostic::{
44 BugAbort, Diag, DiagArg, DiagArgMap, DiagArgName, DiagArgValue, DiagInner, DiagStyledString,
45 Diagnostic, EmissionGuarantee, FatalAbort, IntoDiagArg, LintDiagnostic, StringPart, Subdiag,
46 Subdiagnostic,
47};
48pub use diagnostic_impls::{
49 DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
50 IndicateAnonymousLifetime, SingleLabelManySpans,
51};
52pub use emitter::ColorConfig;
53use emitter::{DynEmitter, Emitter, is_case_difference, is_different};
54use rustc_data_structures::AtomicRef;
55use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
56use rustc_data_structures::stable_hasher::StableHasher;
57use rustc_data_structures::sync::{DynSend, Lock};
58pub use rustc_error_messages::{
59 DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel,
60 SubdiagMessage, fallback_fluent_bundle, fluent_bundle,
61};
62use rustc_hashes::Hash128;
63use rustc_lint_defs::LintExpectationId;
64pub use rustc_lint_defs::{Applicability, listify, pluralize};
65use rustc_macros::{Decodable, Encodable};
66pub use rustc_span::ErrorGuaranteed;
67pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
68use rustc_span::source_map::SourceMap;
69use rustc_span::{BytePos, DUMMY_SP, Loc, Span};
70pub use snippet::Style;
71pub use termcolor::{Color, ColorSpec, WriteColor};
74use tracing::debug;
75
76use crate::registry::Registry;
77
78pub mod annotate_snippet_emitter_writer;
79pub mod codes;
80mod diagnostic;
81mod diagnostic_impls;
82pub mod emitter;
83pub mod error;
84pub mod json;
85mod lock;
86pub mod markdown;
87pub mod registry;
88mod snippet;
89mod styled_buffer;
90#[cfg(test)]
91mod tests;
92pub mod translation;
93
94pub type PResult<'a, T> = Result<T, Diag<'a>>;
95
96rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
97
98#[cfg(target_pointer_width = "64")]
100rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24);
101#[cfg(target_pointer_width = "64")]
102rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24);
103
104#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
105pub enum SuggestionStyle {
106 HideCodeInline,
108 HideCodeAlways,
110 CompletelyHidden,
112 ShowCode,
116 ShowAlways,
118}
119
120impl SuggestionStyle {
121 fn hide_inline(&self) -> bool {
122 !matches!(*self, SuggestionStyle::ShowCode)
123 }
124}
125
126#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
128pub enum Suggestions {
129 Enabled(Vec<CodeSuggestion>),
134 Sealed(Box<[CodeSuggestion]>),
138 Disabled,
142}
143
144impl Suggestions {
145 pub fn unwrap_tag(self) -> Vec<CodeSuggestion> {
147 match self {
148 Suggestions::Enabled(suggestions) => suggestions,
149 Suggestions::Sealed(suggestions) => suggestions.into_vec(),
150 Suggestions::Disabled => Vec::new(),
151 }
152 }
153}
154
155impl Default for Suggestions {
156 fn default() -> Self {
157 Self::Enabled(vec![])
158 }
159}
160
161#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
162pub struct CodeSuggestion {
163 pub substitutions: Vec<Substitution>,
185 pub msg: DiagMessage,
186 pub style: SuggestionStyle,
188 pub applicability: Applicability,
194}
195
196#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
197pub struct Substitution {
199 pub parts: Vec<SubstitutionPart>,
200}
201
202#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
203pub struct SubstitutionPart {
204 pub span: Span,
205 pub snippet: String,
206}
207
208#[derive(Debug, Clone, Copy)]
211pub(crate) struct SubstitutionHighlight {
212 start: usize,
213 end: usize,
214}
215
216impl SubstitutionPart {
217 pub fn is_addition(&self, sm: &SourceMap) -> bool {
218 !self.snippet.is_empty() && !self.replaces_meaningful_content(sm)
219 }
220
221 pub fn is_deletion(&self, sm: &SourceMap) -> bool {
222 self.snippet.trim().is_empty() && self.replaces_meaningful_content(sm)
223 }
224
225 pub fn is_replacement(&self, sm: &SourceMap) -> bool {
226 !self.snippet.is_empty() && self.replaces_meaningful_content(sm)
227 }
228
229 pub fn is_destructive_replacement(&self, sm: &SourceMap) -> bool {
234 self.is_replacement(sm)
235 && !sm
236 .span_to_snippet(self.span)
237 .is_ok_and(|snippet| as_substr(snippet.trim(), self.snippet.trim()).is_some())
238 }
239
240 fn replaces_meaningful_content(&self, sm: &SourceMap) -> bool {
241 sm.span_to_snippet(self.span)
242 .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty())
243 }
244
245 fn trim_trivial_replacements(&mut self, sm: &SourceMap) {
248 if self.snippet.is_empty() {
249 return;
250 }
251 let Ok(snippet) = sm.span_to_snippet(self.span) else {
252 return;
253 };
254
255 if let Some((prefix, substr, suffix)) = as_substr(&snippet, &self.snippet) {
256 self.span = Span::new(
257 self.span.lo() + BytePos(prefix as u32),
258 self.span.hi() - BytePos(suffix as u32),
259 self.span.ctxt(),
260 self.span.parent(),
261 );
262 self.snippet = substr.to_string();
263 }
264 }
265}
266
267fn as_substr<'a>(original: &'a str, suggestion: &'a str) -> Option<(usize, &'a str, usize)> {
272 let common_prefix = original
273 .chars()
274 .zip(suggestion.chars())
275 .take_while(|(c1, c2)| c1 == c2)
276 .map(|(c, _)| c.len_utf8())
277 .sum();
278 let original = &original[common_prefix..];
279 let suggestion = &suggestion[common_prefix..];
280 if suggestion.ends_with(original) {
281 let common_suffix = original.len();
282 Some((common_prefix, &suggestion[..suggestion.len() - original.len()], common_suffix))
283 } else {
284 None
285 }
286}
287
288impl CodeSuggestion {
289 pub(crate) fn splice_lines(
292 &self,
293 sm: &SourceMap,
294 ) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, bool)> {
295 use rustc_span::{CharPos, Pos};
300
301 fn push_trailing(
310 buf: &mut String,
311 line_opt: Option<&Cow<'_, str>>,
312 lo: &Loc,
313 hi_opt: Option<&Loc>,
314 ) -> usize {
315 let mut line_count = 0;
316 let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
319 if let Some(line) = line_opt {
320 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
321 let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
323 match hi_opt {
324 Some(hi) if hi > lo => {
326 line_count = line[lo..hi].matches('\n').count();
328 buf.push_str(&line[lo..hi])
329 }
330 Some(_) => (),
331 None => {
333 line_count = line[lo..].matches('\n').count();
335 buf.push_str(&line[lo..])
336 }
337 }
338 }
339 if hi_opt.is_none() {
341 buf.push('\n');
342 }
343 }
344 line_count
345 }
346
347 assert!(!self.substitutions.is_empty());
348
349 self.substitutions
350 .iter()
351 .filter(|subst| {
352 let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
355 if invalid {
356 debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
357 }
358 !invalid
359 })
360 .cloned()
361 .filter_map(|mut substitution| {
362 substitution.parts.sort_by_key(|part| part.span.lo());
365
366 let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
368 let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
369 let bounding_span = Span::with_root_ctxt(lo, hi);
370 let lines = sm.span_to_lines(bounding_span).ok()?;
372 assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
373
374 if !sm.ensure_source_file_source_present(&lines.file) {
376 return None;
377 }
378
379 let mut highlights = vec![];
380 let sf = &lines.file;
390 let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
391 prev_hi.col = CharPos::from_usize(0);
392 let mut prev_line =
393 lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
394 let mut buf = String::new();
395
396 let mut line_highlight = vec![];
397 let mut acc = 0;
400 let mut only_capitalization = false;
401 for part in &mut substitution.parts {
402 part.trim_trivial_replacements(sm);
406
407 only_capitalization |= is_case_difference(sm, &part.snippet, part.span);
408 let cur_lo = sm.lookup_char_pos(part.span.lo());
409 if prev_hi.line == cur_lo.line {
410 let mut count =
411 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
412 while count > 0 {
413 highlights.push(std::mem::take(&mut line_highlight));
414 acc = 0;
415 count -= 1;
416 }
417 } else {
418 acc = 0;
419 highlights.push(std::mem::take(&mut line_highlight));
420 let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
421 while count > 0 {
422 highlights.push(std::mem::take(&mut line_highlight));
423 count -= 1;
424 }
425 for idx in prev_hi.line..(cur_lo.line - 1) {
427 if let Some(line) = sf.get_line(idx) {
428 buf.push_str(line.as_ref());
429 buf.push('\n');
430 highlights.push(std::mem::take(&mut line_highlight));
431 }
432 }
433 if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
434 let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
435 Some((i, _)) => i,
436 None => cur_line.len(),
437 };
438 buf.push_str(&cur_line[..end]);
439 }
440 }
441 let len: isize = part
443 .snippet
444 .split('\n')
445 .next()
446 .unwrap_or(&part.snippet)
447 .chars()
448 .map(|c| match c {
449 '\t' => 4,
450 _ => 1,
451 })
452 .sum();
453 if !is_different(sm, &part.snippet, part.span) {
454 } else {
458 line_highlight.push(SubstitutionHighlight {
459 start: (cur_lo.col.0 as isize + acc) as usize,
460 end: (cur_lo.col.0 as isize + acc + len) as usize,
461 });
462 }
463 buf.push_str(&part.snippet);
464 let cur_hi = sm.lookup_char_pos(part.span.hi());
465 acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
470 prev_hi = cur_hi;
471 prev_line = sf.get_line(prev_hi.line - 1);
472 for line in part.snippet.split('\n').skip(1) {
473 acc = 0;
474 highlights.push(std::mem::take(&mut line_highlight));
475 let end: usize = line
476 .chars()
477 .map(|c| match c {
478 '\t' => 4,
479 _ => 1,
480 })
481 .sum();
482 line_highlight.push(SubstitutionHighlight { start: 0, end });
483 }
484 }
485 highlights.push(std::mem::take(&mut line_highlight));
486 if !buf.ends_with('\n') {
488 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
489 }
490 while buf.ends_with('\n') {
492 buf.pop();
493 }
494 if highlights.iter().all(|parts| parts.is_empty()) {
495 None
496 } else {
497 Some((buf, substitution.parts, highlights, only_capitalization))
498 }
499 })
500 .collect()
501 }
502}
503
504pub struct ExplicitBug;
507
508pub struct DelayedBugPanic;
511
512pub struct DiagCtxt {
516 inner: Lock<DiagCtxtInner>,
517}
518
519#[derive(Copy, Clone)]
520pub struct DiagCtxtHandle<'a> {
521 dcx: &'a DiagCtxt,
522 tainted_with_errors: Option<&'a Cell<Option<ErrorGuaranteed>>>,
525}
526
527impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
528 type Target = &'a DiagCtxt;
529
530 fn deref(&self) -> &Self::Target {
531 &self.dcx
532 }
533}
534
535struct DiagCtxtInner {
539 flags: DiagCtxtFlags,
540
541 registry: Registry,
542
543 err_guars: Vec<ErrorGuaranteed>,
545 lint_err_guars: Vec<ErrorGuaranteed>,
548 delayed_bugs: Vec<(DelayedDiagInner, ErrorGuaranteed)>,
550
551 deduplicated_err_count: usize,
553 deduplicated_warn_count: usize,
555
556 emitter: Box<DynEmitter>,
557
558 must_produce_diag: Option<Backtrace>,
561
562 has_printed: bool,
565
566 suppressed_expected_diag: bool,
569
570 taught_diagnostics: FxHashSet<ErrCode>,
574
575 emitted_diagnostic_codes: FxIndexSet<ErrCode>,
577
578 emitted_diagnostics: FxHashSet<Hash128>,
582
583 stashed_diagnostics:
589 FxIndexMap<StashKey, FxIndexMap<Span, (DiagInner, Option<ErrorGuaranteed>)>>,
590
591 future_breakage_diagnostics: Vec<DiagInner>,
592
593 fulfilled_expectations: FxIndexSet<LintExpectationId>,
605
606 ice_file: Option<PathBuf>,
609}
610
611#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
613pub enum StashKey {
614 ItemNoType,
615 UnderscoreForArrayLengths,
616 EarlySyntaxWarning,
617 CallIntoMethod,
618 LifetimeIsChar,
621 MaybeFruTypo,
624 CallAssocMethod,
625 AssociatedTypeSuggestion,
626 Cycle,
628 UndeterminedMacroResolution,
629 ExprInPat,
631 GenericInFieldExpr,
635}
636
637fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
638 (*f)(diag)
639}
640
641pub static TRACK_DIAGNOSTIC: AtomicRef<
644 fn(DiagInner, &mut dyn FnMut(DiagInner) -> Option<ErrorGuaranteed>) -> Option<ErrorGuaranteed>,
645> = AtomicRef::new(&(default_track_diagnostic as _));
646
647#[derive(Copy, Clone, Default)]
648pub struct DiagCtxtFlags {
649 pub can_emit_warnings: bool,
652 pub treat_err_as_bug: Option<NonZero<usize>>,
655 pub eagerly_emit_delayed_bugs: bool,
658 pub macro_backtrace: bool,
661 pub deduplicate_diagnostics: bool,
663 pub track_diagnostics: bool,
665}
666
667impl Drop for DiagCtxtInner {
668 fn drop(&mut self) {
669 self.emit_stashed_diagnostics();
677
678 self.flush_delayed();
682
683 if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
687 if let Some(backtrace) = &self.must_produce_diag {
688 let suggestion = match backtrace.status() {
689 BacktraceStatus::Disabled => String::from(
690 "Backtraces are currently disabled: set `RUST_BACKTRACE=1` and re-run \
691 to see where it happened.",
692 ),
693 BacktraceStatus::Captured => format!(
694 "This happened in the following `must_produce_diag` call's backtrace:\n\
695 {backtrace}",
696 ),
697 _ => String::from("(impossible to capture backtrace where this happened)"),
698 };
699 panic!(
700 "`trimmed_def_paths` called, diagnostics were expected but none were emitted. \
701 Use `with_no_trimmed_paths` for debugging. {suggestion}"
702 );
703 }
704 }
705 }
706}
707
708impl DiagCtxt {
709 pub fn disable_warnings(mut self) -> Self {
710 self.inner.get_mut().flags.can_emit_warnings = false;
711 self
712 }
713
714 pub fn with_flags(mut self, flags: DiagCtxtFlags) -> Self {
715 self.inner.get_mut().flags = flags;
716 self
717 }
718
719 pub fn with_ice_file(mut self, ice_file: PathBuf) -> Self {
720 self.inner.get_mut().ice_file = Some(ice_file);
721 self
722 }
723
724 pub fn with_registry(mut self, registry: Registry) -> Self {
725 self.inner.get_mut().registry = registry;
726 self
727 }
728
729 pub fn new(emitter: Box<DynEmitter>) -> Self {
730 Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
731 }
732
733 pub fn make_silent(&self, fatal_note: Option<String>, emit_fatal_diagnostic: bool) {
734 struct FalseEmitter;
737
738 impl Emitter for FalseEmitter {
739 fn emit_diagnostic(&mut self, _: DiagInner, _: &Registry) {
740 unimplemented!("false emitter must only used during `make_silent`")
741 }
742
743 fn source_map(&self) -> Option<&SourceMap> {
744 unimplemented!("false emitter must only used during `make_silent`")
745 }
746 }
747
748 impl translation::Translate for FalseEmitter {
749 fn fluent_bundle(&self) -> Option<&FluentBundle> {
750 unimplemented!("false emitter must only used during `make_silent`")
751 }
752
753 fn fallback_fluent_bundle(&self) -> &FluentBundle {
754 unimplemented!("false emitter must only used during `make_silent`")
755 }
756 }
757
758 let mut inner = self.inner.borrow_mut();
759 let mut prev_emitter = Box::new(FalseEmitter) as Box<dyn Emitter + DynSend>;
760 std::mem::swap(&mut inner.emitter, &mut prev_emitter);
761 let new_emitter = Box::new(emitter::SilentEmitter {
762 fatal_emitter: prev_emitter,
763 fatal_note,
764 emit_fatal_diagnostic,
765 });
766 inner.emitter = new_emitter;
767 }
768
769 pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) {
770 self.inner.borrow_mut().emitter = emitter;
771 }
772
773 pub fn eagerly_translate<'a>(
775 &self,
776 message: DiagMessage,
777 args: impl Iterator<Item = DiagArg<'a>>,
778 ) -> SubdiagMessage {
779 let inner = self.inner.borrow();
780 inner.eagerly_translate(message, args)
781 }
782
783 pub fn eagerly_translate_to_string<'a>(
785 &self,
786 message: DiagMessage,
787 args: impl Iterator<Item = DiagArg<'a>>,
788 ) -> String {
789 let inner = self.inner.borrow();
790 inner.eagerly_translate_to_string(message, args)
791 }
792
793 pub fn can_emit_warnings(&self) -> bool {
797 self.inner.borrow_mut().flags.can_emit_warnings
798 }
799
800 pub fn reset_err_count(&self) {
806 let mut inner = self.inner.borrow_mut();
809 let DiagCtxtInner {
810 flags: _,
811 registry: _,
812 err_guars,
813 lint_err_guars,
814 delayed_bugs,
815 deduplicated_err_count,
816 deduplicated_warn_count,
817 emitter: _,
818 must_produce_diag,
819 has_printed,
820 suppressed_expected_diag,
821 taught_diagnostics,
822 emitted_diagnostic_codes,
823 emitted_diagnostics,
824 stashed_diagnostics,
825 future_breakage_diagnostics,
826 fulfilled_expectations,
827 ice_file: _,
828 } = inner.deref_mut();
829
830 *err_guars = Default::default();
833 *lint_err_guars = Default::default();
834 *delayed_bugs = Default::default();
835 *deduplicated_err_count = 0;
836 *deduplicated_warn_count = 0;
837 *must_produce_diag = None;
838 *has_printed = false;
839 *suppressed_expected_diag = false;
840 *taught_diagnostics = Default::default();
841 *emitted_diagnostic_codes = Default::default();
842 *emitted_diagnostics = Default::default();
843 *stashed_diagnostics = Default::default();
844 *future_breakage_diagnostics = Default::default();
845 *fulfilled_expectations = Default::default();
846 }
847
848 pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> {
849 DiagCtxtHandle { dcx: self, tainted_with_errors: None }
850 }
851
852 pub fn taintable_handle<'a>(
856 &'a self,
857 tainted_with_errors: &'a Cell<Option<ErrorGuaranteed>>,
858 ) -> DiagCtxtHandle<'a> {
859 DiagCtxtHandle { dcx: self, tainted_with_errors: Some(tainted_with_errors) }
860 }
861}
862
863impl<'a> DiagCtxtHandle<'a> {
864 pub fn stash_diagnostic(
886 &self,
887 span: Span,
888 key: StashKey,
889 diag: DiagInner,
890 ) -> Option<ErrorGuaranteed> {
891 let guar = match diag.level {
892 Bug | Fatal => {
893 self.span_bug(
894 span,
895 format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
896 );
897 }
898 Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
902 DelayedBug => {
903 return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors);
904 }
905 ForceWarning | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
906 | Expect => None,
907 };
908
909 self.inner
913 .borrow_mut()
914 .stashed_diagnostics
915 .entry(key)
916 .or_default()
917 .insert(span.with_parent(None), (diag, guar));
918
919 guar
920 }
921
922 pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
926 let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
928 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
929 )?;
930 assert!(!diag.is_error());
931 assert!(guar.is_none());
932 Some(Diag::new_diagnostic(self, diag))
933 }
934
935 pub fn try_steal_modify_and_emit_err<F>(
940 self,
941 span: Span,
942 key: StashKey,
943 mut modify_err: F,
944 ) -> Option<ErrorGuaranteed>
945 where
946 F: FnMut(&mut Diag<'_>),
947 {
948 let err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
950 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
951 );
952 err.map(|(err, guar)| {
953 assert_eq!(err.level, Error);
955 assert!(guar.is_some());
956 let mut err = Diag::<ErrorGuaranteed>::new_diagnostic(self, err);
957 modify_err(&mut err);
958 assert_eq!(err.level, Error);
959 err.emit()
960 })
961 }
962
963 pub fn try_steal_replace_and_emit_err(
967 self,
968 span: Span,
969 key: StashKey,
970 new_err: Diag<'_>,
971 ) -> ErrorGuaranteed {
972 let old_err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
974 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
975 );
976 match old_err {
977 Some((old_err, guar)) => {
978 assert_eq!(old_err.level, Error);
979 assert!(guar.is_some());
980 Diag::<ErrorGuaranteed>::new_diagnostic(self, old_err).cancel();
983 }
984 None => {}
985 };
986 new_err.emit()
987 }
988
989 pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
990 let inner = self.inner.borrow();
991 if let Some(stashed_diagnostics) = inner.stashed_diagnostics.get(&key)
992 && !stashed_diagnostics.is_empty()
993 {
994 stashed_diagnostics.contains_key(&span.with_parent(None))
995 } else {
996 false
997 }
998 }
999
1000 pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
1002 self.inner.borrow_mut().emit_stashed_diagnostics()
1003 }
1004
1005 #[inline]
1007 pub fn err_count(&self) -> usize {
1008 let inner = self.inner.borrow();
1009 inner.err_guars.len()
1010 + inner.lint_err_guars.len()
1011 + inner
1012 .stashed_diagnostics
1013 .values()
1014 .map(|a| a.values().filter(|(_, guar)| guar.is_some()).count())
1015 .sum::<usize>()
1016 }
1017
1018 pub fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1021 self.inner.borrow().has_errors_excluding_lint_errors()
1022 }
1023
1024 pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
1026 self.inner.borrow().has_errors()
1027 }
1028
1029 pub fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1032 self.inner.borrow().has_errors_or_delayed_bugs()
1033 }
1034
1035 pub fn print_error_count(&self) {
1036 let mut inner = self.inner.borrow_mut();
1037
1038 assert!(inner.stashed_diagnostics.is_empty());
1041
1042 if inner.treat_err_as_bug() {
1043 return;
1044 }
1045
1046 let warnings = match inner.deduplicated_warn_count {
1047 0 => Cow::from(""),
1048 1 => Cow::from("1 warning emitted"),
1049 count => Cow::from(format!("{count} warnings emitted")),
1050 };
1051 let errors = match inner.deduplicated_err_count {
1052 0 => Cow::from(""),
1053 1 => Cow::from("aborting due to 1 previous error"),
1054 count => Cow::from(format!("aborting due to {count} previous errors")),
1055 };
1056
1057 match (errors.len(), warnings.len()) {
1058 (0, 0) => return,
1059 (0, _) => {
1060 inner.emit_diagnostic(
1063 DiagInner::new(ForceWarning, DiagMessage::Str(warnings)),
1064 None,
1065 );
1066 }
1067 (_, 0) => {
1068 inner.emit_diagnostic(DiagInner::new(Error, errors), self.tainted_with_errors);
1069 }
1070 (_, _) => {
1071 inner.emit_diagnostic(
1072 DiagInner::new(Error, format!("{errors}; {warnings}")),
1073 self.tainted_with_errors,
1074 );
1075 }
1076 }
1077
1078 let can_show_explain = inner.emitter.should_show_explain();
1079 let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty();
1080 if can_show_explain && are_there_diagnostics {
1081 let mut error_codes = inner
1082 .emitted_diagnostic_codes
1083 .iter()
1084 .filter_map(|&code| {
1085 if inner.registry.try_find_description(code).is_ok() {
1086 Some(code.to_string())
1087 } else {
1088 None
1089 }
1090 })
1091 .collect::<Vec<_>>();
1092 if !error_codes.is_empty() {
1093 error_codes.sort();
1094 if error_codes.len() > 1 {
1095 let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
1096 let msg1 = format!(
1097 "Some errors have detailed explanations: {}{}",
1098 error_codes[..limit].join(", "),
1099 if error_codes.len() > 9 { "..." } else { "." }
1100 );
1101 let msg2 = format!(
1102 "For more information about an error, try `rustc --explain {}`.",
1103 &error_codes[0]
1104 );
1105 inner.emit_diagnostic(DiagInner::new(FailureNote, msg1), None);
1106 inner.emit_diagnostic(DiagInner::new(FailureNote, msg2), None);
1107 } else {
1108 let msg = format!(
1109 "For more information about this error, try `rustc --explain {}`.",
1110 &error_codes[0]
1111 );
1112 inner.emit_diagnostic(DiagInner::new(FailureNote, msg), None);
1113 }
1114 }
1115 }
1116 }
1117
1118 pub fn abort_if_errors(&self) {
1123 if let Some(guar) = self.has_errors() {
1124 guar.raise_fatal();
1125 }
1126 }
1127
1128 pub fn must_teach(&self, code: ErrCode) -> bool {
1134 self.inner.borrow_mut().taught_diagnostics.insert(code)
1135 }
1136
1137 pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
1138 self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors)
1139 }
1140
1141 pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
1142 self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
1143 }
1144
1145 pub fn emit_future_breakage_report(&self) {
1146 let inner = &mut *self.inner.borrow_mut();
1147 let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
1148 if !diags.is_empty() {
1149 inner.emitter.emit_future_breakage_report(diags, &inner.registry);
1150 }
1151 }
1152
1153 pub fn emit_unused_externs(
1154 &self,
1155 lint_level: rustc_lint_defs::Level,
1156 loud: bool,
1157 unused_externs: &[&str],
1158 ) {
1159 let mut inner = self.inner.borrow_mut();
1160
1161 if loud && lint_level.is_error() {
1172 #[allow(deprecated)]
1175 inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
1176 inner.panic_if_treat_err_as_bug();
1177 }
1178
1179 inner.emitter.emit_unused_externs(lint_level, unused_externs)
1180 }
1181
1182 #[must_use]
1185 pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
1186 std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
1187 }
1188
1189 pub fn flush_delayed(&self) {
1190 self.inner.borrow_mut().flush_delayed();
1191 }
1192
1193 #[track_caller]
1196 pub fn set_must_produce_diag(&self) {
1197 assert!(
1198 self.inner.borrow().must_produce_diag.is_none(),
1199 "should only need to collect a backtrace once"
1200 );
1201 self.inner.borrow_mut().must_produce_diag = Some(Backtrace::capture());
1202 }
1203}
1204
1205impl<'a> DiagCtxtHandle<'a> {
1210 #[track_caller]
1213 pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> {
1214 Diag::new(self, Bug, msg.into())
1215 }
1216
1217 #[track_caller]
1220 pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
1221 self.struct_bug(msg).emit()
1222 }
1223
1224 #[track_caller]
1227 pub fn struct_span_bug(
1228 self,
1229 span: impl Into<MultiSpan>,
1230 msg: impl Into<Cow<'static, str>>,
1231 ) -> Diag<'a, BugAbort> {
1232 self.struct_bug(msg).with_span(span)
1233 }
1234
1235 #[track_caller]
1238 pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
1239 self.struct_span_bug(span, msg.into()).emit()
1240 }
1241
1242 #[track_caller]
1243 pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> {
1244 bug.into_diag(self, Bug)
1245 }
1246
1247 #[track_caller]
1248 pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! {
1249 self.create_bug(bug).emit()
1250 }
1251
1252 #[rustc_lint_diagnostics]
1253 #[track_caller]
1254 pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> {
1255 Diag::new(self, Fatal, msg)
1256 }
1257
1258 #[rustc_lint_diagnostics]
1259 #[track_caller]
1260 pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
1261 self.struct_fatal(msg).emit()
1262 }
1263
1264 #[rustc_lint_diagnostics]
1265 #[track_caller]
1266 pub fn struct_span_fatal(
1267 self,
1268 span: impl Into<MultiSpan>,
1269 msg: impl Into<DiagMessage>,
1270 ) -> Diag<'a, FatalAbort> {
1271 self.struct_fatal(msg).with_span(span)
1272 }
1273
1274 #[rustc_lint_diagnostics]
1275 #[track_caller]
1276 pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
1277 self.struct_span_fatal(span, msg).emit()
1278 }
1279
1280 #[track_caller]
1281 pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> {
1282 fatal.into_diag(self, Fatal)
1283 }
1284
1285 #[track_caller]
1286 pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
1287 self.create_fatal(fatal).emit()
1288 }
1289
1290 #[track_caller]
1291 pub fn create_almost_fatal(
1292 self,
1293 fatal: impl Diagnostic<'a, FatalError>,
1294 ) -> Diag<'a, FatalError> {
1295 fatal.into_diag(self, Fatal)
1296 }
1297
1298 #[track_caller]
1299 pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError {
1300 self.create_almost_fatal(fatal).emit()
1301 }
1302
1303 #[rustc_lint_diagnostics]
1305 #[track_caller]
1306 pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> {
1307 Diag::new(self, Error, msg)
1308 }
1309
1310 #[rustc_lint_diagnostics]
1311 #[track_caller]
1312 pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
1313 self.struct_err(msg).emit()
1314 }
1315
1316 #[rustc_lint_diagnostics]
1317 #[track_caller]
1318 pub fn struct_span_err(
1319 self,
1320 span: impl Into<MultiSpan>,
1321 msg: impl Into<DiagMessage>,
1322 ) -> Diag<'a> {
1323 self.struct_err(msg).with_span(span)
1324 }
1325
1326 #[rustc_lint_diagnostics]
1327 #[track_caller]
1328 pub fn span_err(
1329 self,
1330 span: impl Into<MultiSpan>,
1331 msg: impl Into<DiagMessage>,
1332 ) -> ErrorGuaranteed {
1333 self.struct_span_err(span, msg).emit()
1334 }
1335
1336 #[track_caller]
1337 pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> {
1338 err.into_diag(self, Error)
1339 }
1340
1341 #[track_caller]
1342 pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
1343 self.create_err(err).emit()
1344 }
1345
1346 #[track_caller]
1351 pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
1352 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
1353 }
1354
1355 #[track_caller]
1363 pub fn span_delayed_bug(
1364 self,
1365 sp: impl Into<MultiSpan>,
1366 msg: impl Into<Cow<'static, str>>,
1367 ) -> ErrorGuaranteed {
1368 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
1369 }
1370
1371 #[rustc_lint_diagnostics]
1372 #[track_caller]
1373 pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1374 Diag::new(self, Warning, msg)
1375 }
1376
1377 #[rustc_lint_diagnostics]
1378 #[track_caller]
1379 pub fn warn(self, msg: impl Into<DiagMessage>) {
1380 self.struct_warn(msg).emit()
1381 }
1382
1383 #[rustc_lint_diagnostics]
1384 #[track_caller]
1385 pub fn struct_span_warn(
1386 self,
1387 span: impl Into<MultiSpan>,
1388 msg: impl Into<DiagMessage>,
1389 ) -> Diag<'a, ()> {
1390 self.struct_warn(msg).with_span(span)
1391 }
1392
1393 #[rustc_lint_diagnostics]
1394 #[track_caller]
1395 pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1396 self.struct_span_warn(span, msg).emit()
1397 }
1398
1399 #[track_caller]
1400 pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1401 warning.into_diag(self, Warning)
1402 }
1403
1404 #[track_caller]
1405 pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) {
1406 self.create_warn(warning).emit()
1407 }
1408
1409 #[rustc_lint_diagnostics]
1410 #[track_caller]
1411 pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1412 Diag::new(self, Note, msg)
1413 }
1414
1415 #[rustc_lint_diagnostics]
1416 #[track_caller]
1417 pub fn note(&self, msg: impl Into<DiagMessage>) {
1418 self.struct_note(msg).emit()
1419 }
1420
1421 #[rustc_lint_diagnostics]
1422 #[track_caller]
1423 pub fn struct_span_note(
1424 self,
1425 span: impl Into<MultiSpan>,
1426 msg: impl Into<DiagMessage>,
1427 ) -> Diag<'a, ()> {
1428 self.struct_note(msg).with_span(span)
1429 }
1430
1431 #[rustc_lint_diagnostics]
1432 #[track_caller]
1433 pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1434 self.struct_span_note(span, msg).emit()
1435 }
1436
1437 #[track_caller]
1438 pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1439 note.into_diag(self, Note)
1440 }
1441
1442 #[track_caller]
1443 pub fn emit_note(self, note: impl Diagnostic<'a, ()>) {
1444 self.create_note(note).emit()
1445 }
1446
1447 #[rustc_lint_diagnostics]
1448 #[track_caller]
1449 pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1450 Diag::new(self, Help, msg)
1451 }
1452
1453 #[rustc_lint_diagnostics]
1454 #[track_caller]
1455 pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1456 Diag::new(self, FailureNote, msg)
1457 }
1458
1459 #[rustc_lint_diagnostics]
1460 #[track_caller]
1461 pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1462 Diag::new(self, Allow, msg)
1463 }
1464
1465 #[rustc_lint_diagnostics]
1466 #[track_caller]
1467 pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> {
1468 Diag::new(self, Expect, msg).with_lint_id(id)
1469 }
1470}
1471
1472impl DiagCtxtInner {
1477 fn new(emitter: Box<DynEmitter>) -> Self {
1478 Self {
1479 flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
1480 registry: Registry::new(&[]),
1481 err_guars: Vec::new(),
1482 lint_err_guars: Vec::new(),
1483 delayed_bugs: Vec::new(),
1484 deduplicated_err_count: 0,
1485 deduplicated_warn_count: 0,
1486 emitter,
1487 must_produce_diag: None,
1488 has_printed: false,
1489 suppressed_expected_diag: false,
1490 taught_diagnostics: Default::default(),
1491 emitted_diagnostic_codes: Default::default(),
1492 emitted_diagnostics: Default::default(),
1493 stashed_diagnostics: Default::default(),
1494 future_breakage_diagnostics: Vec::new(),
1495 fulfilled_expectations: Default::default(),
1496 ice_file: None,
1497 }
1498 }
1499
1500 fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
1502 let mut guar = None;
1503 let has_errors = !self.err_guars.is_empty();
1504 for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
1505 for (_, (diag, _guar)) in stashed_diagnostics {
1506 if !diag.is_error() {
1507 if !diag.is_force_warn() && has_errors {
1511 continue;
1512 }
1513 }
1514 guar = guar.or(self.emit_diagnostic(diag, None));
1515 }
1516 }
1517 guar
1518 }
1519
1520 fn emit_diagnostic(
1522 &mut self,
1523 mut diagnostic: DiagInner,
1524 taint: Option<&Cell<Option<ErrorGuaranteed>>>,
1525 ) -> Option<ErrorGuaranteed> {
1526 if diagnostic.has_future_breakage() {
1527 assert_matches!(diagnostic.level, Error | ForceWarning | Warning | Allow | Expect);
1531 self.future_breakage_diagnostics.push(diagnostic.clone());
1532 }
1533
1534 match diagnostic.level {
1538 Bug => {}
1539 Fatal | Error => {
1540 if self.treat_next_err_as_bug() {
1541 diagnostic.level = Bug;
1543 }
1544 }
1545 DelayedBug => {
1546 if self.flags.eagerly_emit_delayed_bugs {
1551 if self.treat_next_err_as_bug() {
1553 diagnostic.level = Bug;
1554 } else {
1555 diagnostic.level = Error;
1556 }
1557 } else {
1558 return if let Some(guar) = self.has_errors() {
1561 Some(guar)
1562 } else {
1563 let backtrace = std::backtrace::Backtrace::capture();
1567 #[allow(deprecated)]
1571 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1572 self.delayed_bugs
1573 .push((DelayedDiagInner::with_backtrace(diagnostic, backtrace), guar));
1574 Some(guar)
1575 };
1576 }
1577 }
1578 ForceWarning if diagnostic.lint_id.is_none() => {} Warning => {
1580 if !self.flags.can_emit_warnings {
1581 if diagnostic.has_future_breakage() {
1583 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1585 }
1586 return None;
1587 }
1588 }
1589 Note | Help | FailureNote => {}
1590 OnceNote | OnceHelp => panic!("bad level: {:?}", diagnostic.level),
1591 Allow => {
1592 if diagnostic.has_future_breakage() {
1594 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1596 self.suppressed_expected_diag = true;
1597 }
1598 return None;
1599 }
1600 Expect | ForceWarning => {
1601 self.fulfilled_expectations.insert(diagnostic.lint_id.unwrap());
1602 if let Expect = diagnostic.level {
1603 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1605 self.suppressed_expected_diag = true;
1606 return None;
1607 }
1608 }
1609 }
1610
1611 TRACK_DIAGNOSTIC(diagnostic, &mut |mut diagnostic| {
1612 if let Some(code) = diagnostic.code {
1613 self.emitted_diagnostic_codes.insert(code);
1614 }
1615
1616 let already_emitted = {
1617 let mut hasher = StableHasher::new();
1618 diagnostic.hash(&mut hasher);
1619 let diagnostic_hash = hasher.finish();
1620 !self.emitted_diagnostics.insert(diagnostic_hash)
1621 };
1622
1623 let is_error = diagnostic.is_error();
1624 let is_lint = diagnostic.is_lint.is_some();
1625
1626 if !(self.flags.deduplicate_diagnostics && already_emitted) {
1629 debug!(?diagnostic);
1630 debug!(?self.emitted_diagnostics);
1631
1632 let not_yet_emitted = |sub: &mut Subdiag| {
1633 debug!(?sub);
1634 if sub.level != OnceNote && sub.level != OnceHelp {
1635 return true;
1636 }
1637 let mut hasher = StableHasher::new();
1638 sub.hash(&mut hasher);
1639 let diagnostic_hash = hasher.finish();
1640 debug!(?diagnostic_hash);
1641 self.emitted_diagnostics.insert(diagnostic_hash)
1642 };
1643 diagnostic.children.retain_mut(not_yet_emitted);
1644 if already_emitted {
1645 let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`";
1646 diagnostic.sub(Note, msg, MultiSpan::new());
1647 }
1648
1649 if is_error {
1650 self.deduplicated_err_count += 1;
1651 } else if matches!(diagnostic.level, ForceWarning | Warning) {
1652 self.deduplicated_warn_count += 1;
1653 }
1654 self.has_printed = true;
1655
1656 self.emitter.emit_diagnostic(diagnostic, &self.registry);
1657 }
1658
1659 if is_error {
1660 if !self.delayed_bugs.is_empty() {
1665 assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0);
1666 self.delayed_bugs.clear();
1667 self.delayed_bugs.shrink_to_fit();
1668 }
1669
1670 #[allow(deprecated)]
1673 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1674 if is_lint {
1675 self.lint_err_guars.push(guar);
1676 } else {
1677 if let Some(taint) = taint {
1678 taint.set(Some(guar));
1679 }
1680 self.err_guars.push(guar);
1681 }
1682 self.panic_if_treat_err_as_bug();
1683 Some(guar)
1684 } else {
1685 None
1686 }
1687 })
1688 }
1689
1690 fn treat_err_as_bug(&self) -> bool {
1691 self.flags
1692 .treat_err_as_bug
1693 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
1694 }
1695
1696 fn treat_next_err_as_bug(&self) -> bool {
1698 self.flags
1699 .treat_err_as_bug
1700 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
1701 }
1702
1703 fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1704 self.err_guars.get(0).copied().or_else(|| {
1705 if let Some((_diag, guar)) = self
1706 .stashed_diagnostics
1707 .values()
1708 .flat_map(|stashed_diagnostics| stashed_diagnostics.values())
1709 .find(|(diag, guar)| guar.is_some() && diag.is_lint.is_none())
1710 {
1711 *guar
1712 } else {
1713 None
1714 }
1715 })
1716 }
1717
1718 fn has_errors(&self) -> Option<ErrorGuaranteed> {
1719 self.err_guars.get(0).copied().or_else(|| self.lint_err_guars.get(0).copied()).or_else(
1720 || {
1721 self.stashed_diagnostics.values().find_map(|stashed_diagnostics| {
1722 stashed_diagnostics.values().find_map(|(_, guar)| *guar)
1723 })
1724 },
1725 )
1726 }
1727
1728 fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1729 self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
1730 }
1731
1732 fn eagerly_translate<'a>(
1734 &self,
1735 message: DiagMessage,
1736 args: impl Iterator<Item = DiagArg<'a>>,
1737 ) -> SubdiagMessage {
1738 SubdiagMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
1739 }
1740
1741 fn eagerly_translate_to_string<'a>(
1743 &self,
1744 message: DiagMessage,
1745 args: impl Iterator<Item = DiagArg<'a>>,
1746 ) -> String {
1747 let args = crate::translation::to_fluent_args(args);
1748 self.emitter.translate_message(&message, &args).map_err(Report::new).unwrap().to_string()
1749 }
1750
1751 fn eagerly_translate_for_subdiag(
1752 &self,
1753 diag: &DiagInner,
1754 msg: impl Into<SubdiagMessage>,
1755 ) -> SubdiagMessage {
1756 let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
1757 self.eagerly_translate(msg, diag.args.iter())
1758 }
1759
1760 fn flush_delayed(&mut self) {
1761 assert!(self.stashed_diagnostics.is_empty());
1765
1766 if !self.err_guars.is_empty() {
1767 return;
1769 }
1770
1771 if self.delayed_bugs.is_empty() {
1772 return;
1774 }
1775
1776 let bugs: Vec<_> =
1777 std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
1778
1779 let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0"));
1780 let decorate = backtrace || self.ice_file.is_none();
1781 let mut out = self
1782 .ice_file
1783 .as_ref()
1784 .and_then(|file| std::fs::File::options().create(true).append(true).open(file).ok());
1785
1786 let note1 = "no errors encountered even though delayed bugs were created";
1791 let note2 = "those delayed bugs will now be shown as internal compiler errors";
1792 self.emit_diagnostic(DiagInner::new(Note, note1), None);
1793 self.emit_diagnostic(DiagInner::new(Note, note2), None);
1794
1795 for bug in bugs {
1796 if let Some(out) = &mut out {
1797 _ = write!(
1798 out,
1799 "delayed bug: {}\n{}\n",
1800 bug.inner
1801 .messages
1802 .iter()
1803 .filter_map(|(msg, _)| msg.as_str())
1804 .collect::<String>(),
1805 &bug.note
1806 );
1807 }
1808
1809 let mut bug = if decorate { bug.decorate(self) } else { bug.inner };
1810
1811 if bug.level != DelayedBug {
1813 bug.arg("level", bug.level);
1820 let msg = crate::fluent_generated::errors_invalid_flushed_delayed_diagnostic_level;
1821 let msg = self.eagerly_translate_for_subdiag(&bug, msg); bug.sub(Note, msg, bug.span.primary_span().unwrap().into());
1823 }
1824 bug.level = Bug;
1825
1826 self.emit_diagnostic(bug, None);
1827 }
1828
1829 panic::panic_any(DelayedBugPanic);
1831 }
1832
1833 fn panic_if_treat_err_as_bug(&self) {
1834 if self.treat_err_as_bug() {
1835 let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
1836 assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
1837 if n == 1 {
1838 panic!("aborting due to `-Z treat-err-as-bug=1`");
1839 } else {
1840 panic!("aborting after {n} errors due to `-Z treat-err-as-bug={n}`");
1841 }
1842 }
1843 }
1844}
1845
1846struct DelayedDiagInner {
1847 inner: DiagInner,
1848 note: Backtrace,
1849}
1850
1851impl DelayedDiagInner {
1852 fn with_backtrace(diagnostic: DiagInner, backtrace: Backtrace) -> Self {
1853 DelayedDiagInner { inner: diagnostic, note: backtrace }
1854 }
1855
1856 fn decorate(self, dcx: &DiagCtxtInner) -> DiagInner {
1857 let mut diag = self.inner;
1861 let msg = match self.note.status() {
1862 BacktraceStatus::Captured => crate::fluent_generated::errors_delayed_at_with_newline,
1863 _ => crate::fluent_generated::errors_delayed_at_without_newline,
1866 };
1867 diag.arg("emitted_at", diag.emitted_at.clone());
1868 diag.arg("note", self.note);
1869 let msg = dcx.eagerly_translate_for_subdiag(&diag, msg); diag.sub(Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into());
1871 diag
1872 }
1873}
1874
1875#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
1895pub enum Level {
1896 Bug,
1898
1899 Fatal,
1902
1903 Error,
1906
1907 DelayedBug,
1912
1913 ForceWarning,
1919
1920 Warning,
1923
1924 Note,
1926
1927 OnceNote,
1929
1930 Help,
1932
1933 OnceHelp,
1935
1936 FailureNote,
1939
1940 Allow,
1942
1943 Expect,
1945}
1946
1947impl fmt::Display for Level {
1948 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1949 self.to_str().fmt(f)
1950 }
1951}
1952
1953impl Level {
1954 fn color(self) -> ColorSpec {
1955 let mut spec = ColorSpec::new();
1956 match self {
1957 Bug | Fatal | Error | DelayedBug => {
1958 spec.set_fg(Some(Color::Red)).set_intense(true);
1959 }
1960 ForceWarning | Warning => {
1961 spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
1962 }
1963 Note | OnceNote => {
1964 spec.set_fg(Some(Color::Green)).set_intense(true);
1965 }
1966 Help | OnceHelp => {
1967 spec.set_fg(Some(Color::Cyan)).set_intense(true);
1968 }
1969 FailureNote => {}
1970 Allow | Expect => unreachable!(),
1971 }
1972 spec
1973 }
1974
1975 pub fn to_str(self) -> &'static str {
1976 match self {
1977 Bug | DelayedBug => "error: internal compiler error",
1978 Fatal | Error => "error",
1979 ForceWarning | Warning => "warning",
1980 Note | OnceNote => "note",
1981 Help | OnceHelp => "help",
1982 FailureNote => "failure-note",
1983 Allow | Expect => unreachable!(),
1984 }
1985 }
1986
1987 pub fn is_failure_note(&self) -> bool {
1988 matches!(*self, FailureNote)
1989 }
1990
1991 fn can_be_subdiag(&self) -> bool {
1993 match self {
1994 Bug | DelayedBug | Fatal | Error | ForceWarning | FailureNote | Allow | Expect => false,
1995
1996 Warning | Note | Help | OnceNote | OnceHelp => true,
1997 }
1998 }
1999}
2000
2001pub fn elided_lifetime_in_path_suggestion(
2003 source_map: &SourceMap,
2004 n: usize,
2005 path_span: Span,
2006 incl_angl_brckt: bool,
2007 insertion_span: Span,
2008) -> ElidedLifetimeInPathSubdiag {
2009 let expected = ExpectedLifetimeParameter { span: path_span, count: n };
2010 let indicate = source_map.is_span_accessible(insertion_span).then(|| {
2012 let anon_lts = vec!["'_"; n].join(", ");
2013 let suggestion =
2014 if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
2015
2016 IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
2017 });
2018
2019 ElidedLifetimeInPathSubdiag { expected, indicate }
2020}
2021
2022pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
2023 diag: &mut Diag<'a, G>,
2024 ambiguity: rustc_lint_defs::AmbiguityErrorDiag,
2025) {
2026 diag.span_label(ambiguity.label_span, ambiguity.label_msg);
2027 diag.note(ambiguity.note_msg);
2028 diag.span_note(ambiguity.b1_span, ambiguity.b1_note_msg);
2029 for help_msg in ambiguity.b1_help_msgs {
2030 diag.help(help_msg);
2031 }
2032 diag.span_note(ambiguity.b2_span, ambiguity.b2_note_msg);
2033 for help_msg in ambiguity.b2_help_msgs {
2034 diag.help(help_msg);
2035 }
2036}
2037
2038pub fn a_or_an(s: &str) -> &'static str {
2042 let mut chars = s.chars();
2043 let Some(mut first_alpha_char) = chars.next() else {
2044 return "a";
2045 };
2046 if first_alpha_char == '`' {
2047 let Some(next) = chars.next() else {
2048 return "a";
2049 };
2050 first_alpha_char = next;
2051 }
2052 if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
2053 "an"
2054 } else {
2055 "a"
2056 }
2057}
2058
2059#[derive(Clone, Copy, PartialEq, Hash, Debug)]
2060pub enum TerminalUrl {
2061 No,
2062 Yes,
2063 Auto,
2064}