1#![allow(incomplete_features)]
7#![allow(internal_features)]
8#![allow(rustc::diagnostic_outside_of_impl)]
9#![allow(rustc::untranslatable_diagnostic)]
10#![cfg_attr(bootstrap, feature(let_chains))]
11#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
12#![doc(rust_logo)]
13#![feature(array_windows)]
14#![feature(assert_matches)]
15#![feature(associated_type_defaults)]
16#![feature(box_into_inner)]
17#![feature(box_patterns)]
18#![feature(default_field_values)]
19#![feature(error_reporter)]
20#![feature(if_let_guard)]
21#![feature(negative_impls)]
22#![feature(never_type)]
23#![feature(rustc_attrs)]
24#![feature(rustdoc_internals)]
25#![feature(trait_alias)]
26#![feature(try_blocks)]
27#![feature(yeet_expr)]
28extern crate self as rustc_errors;
31
32use std::assert_matches::assert_matches;
33use std::backtrace::{Backtrace, BacktraceStatus};
34use std::borrow::Cow;
35use std::cell::Cell;
36use std::error::Report;
37use std::ffi::OsStr;
38use std::hash::Hash;
39use std::io::Write;
40use std::num::NonZero;
41use std::ops::DerefMut;
42use std::path::{Path, PathBuf};
43use std::{fmt, panic};
44
45use Level::*;
46pub use codes::*;
47pub use diagnostic::{
48 BugAbort, Diag, DiagArg, DiagArgMap, DiagArgName, DiagArgValue, DiagInner, DiagStyledString,
49 Diagnostic, EmissionGuarantee, FatalAbort, IntoDiagArg, LintDiagnostic, StringPart, Subdiag,
50 Subdiagnostic,
51};
52pub use diagnostic_impls::{
53 DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
54 IndicateAnonymousLifetime, SingleLabelManySpans,
55};
56pub use emitter::ColorConfig;
57use emitter::{DynEmitter, Emitter, is_case_difference, is_different};
58use rustc_data_structures::AtomicRef;
59use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
60use rustc_data_structures::stable_hasher::StableHasher;
61use rustc_data_structures::sync::{DynSend, Lock};
62pub use rustc_error_messages::{
63 DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel,
64 SubdiagMessage, fallback_fluent_bundle, fluent_bundle,
65};
66use rustc_hashes::Hash128;
67use rustc_lint_defs::LintExpectationId;
68pub use rustc_lint_defs::{Applicability, listify, pluralize};
69use rustc_macros::{Decodable, Encodable};
70pub use rustc_span::ErrorGuaranteed;
71pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
72use rustc_span::source_map::SourceMap;
73use rustc_span::{BytePos, DUMMY_SP, Loc, Span};
74pub use snippet::Style;
75pub use termcolor::{Color, ColorSpec, WriteColor};
78use tracing::debug;
79
80use crate::registry::Registry;
81
82pub mod annotate_snippet_emitter_writer;
83pub mod codes;
84mod diagnostic;
85mod diagnostic_impls;
86pub mod emitter;
87pub mod error;
88pub mod json;
89mod lock;
90pub mod markdown;
91pub mod registry;
92mod snippet;
93mod styled_buffer;
94#[cfg(test)]
95mod tests;
96pub mod translation;
97
98pub type PResult<'a, T> = Result<T, Diag<'a>>;
99
100rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
101
102#[cfg(target_pointer_width = "64")]
104rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24);
105#[cfg(target_pointer_width = "64")]
106rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24);
107
108#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
109pub enum SuggestionStyle {
110 HideCodeInline,
112 HideCodeAlways,
114 CompletelyHidden,
116 ShowCode,
120 ShowAlways,
122}
123
124impl SuggestionStyle {
125 fn hide_inline(&self) -> bool {
126 !matches!(*self, SuggestionStyle::ShowCode)
127 }
128}
129
130#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
132pub enum Suggestions {
133 Enabled(Vec<CodeSuggestion>),
138 Sealed(Box<[CodeSuggestion]>),
142 Disabled,
146}
147
148impl Suggestions {
149 pub fn unwrap_tag(self) -> Vec<CodeSuggestion> {
151 match self {
152 Suggestions::Enabled(suggestions) => suggestions,
153 Suggestions::Sealed(suggestions) => suggestions.into_vec(),
154 Suggestions::Disabled => Vec::new(),
155 }
156 }
157}
158
159impl Default for Suggestions {
160 fn default() -> Self {
161 Self::Enabled(vec![])
162 }
163}
164
165#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
166pub struct CodeSuggestion {
167 pub substitutions: Vec<Substitution>,
189 pub msg: DiagMessage,
190 pub style: SuggestionStyle,
192 pub applicability: Applicability,
198}
199
200#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
201pub struct Substitution {
203 pub parts: Vec<SubstitutionPart>,
204}
205
206#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
207pub struct SubstitutionPart {
208 pub span: Span,
209 pub snippet: String,
210}
211
212#[derive(Debug, Clone, Copy)]
215pub(crate) struct SubstitutionHighlight {
216 start: usize,
217 end: usize,
218}
219
220impl SubstitutionPart {
221 pub fn is_addition(&self, sm: &SourceMap) -> bool {
222 !self.snippet.is_empty() && !self.replaces_meaningful_content(sm)
223 }
224
225 pub fn is_deletion(&self, sm: &SourceMap) -> bool {
226 self.snippet.trim().is_empty() && self.replaces_meaningful_content(sm)
227 }
228
229 pub fn is_replacement(&self, sm: &SourceMap) -> bool {
230 !self.snippet.is_empty() && self.replaces_meaningful_content(sm)
231 }
232
233 pub fn is_destructive_replacement(&self, sm: &SourceMap) -> bool {
238 self.is_replacement(sm)
239 && !sm
240 .span_to_snippet(self.span)
241 .is_ok_and(|snippet| as_substr(snippet.trim(), self.snippet.trim()).is_some())
242 }
243
244 fn replaces_meaningful_content(&self, sm: &SourceMap) -> bool {
245 sm.span_to_snippet(self.span)
246 .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty())
247 }
248
249 fn trim_trivial_replacements(&mut self, sm: &SourceMap) {
252 if self.snippet.is_empty() {
253 return;
254 }
255 let Ok(snippet) = sm.span_to_snippet(self.span) else {
256 return;
257 };
258
259 if let Some((prefix, substr, suffix)) = as_substr(&snippet, &self.snippet) {
260 self.span = Span::new(
261 self.span.lo() + BytePos(prefix as u32),
262 self.span.hi() - BytePos(suffix as u32),
263 self.span.ctxt(),
264 self.span.parent(),
265 );
266 self.snippet = substr.to_string();
267 }
268 }
269}
270
271fn as_substr<'a>(original: &'a str, suggestion: &'a str) -> Option<(usize, &'a str, usize)> {
276 let common_prefix = original
277 .chars()
278 .zip(suggestion.chars())
279 .take_while(|(c1, c2)| c1 == c2)
280 .map(|(c, _)| c.len_utf8())
281 .sum();
282 let original = &original[common_prefix..];
283 let suggestion = &suggestion[common_prefix..];
284 if suggestion.ends_with(original) {
285 let common_suffix = original.len();
286 Some((common_prefix, &suggestion[..suggestion.len() - original.len()], common_suffix))
287 } else {
288 None
289 }
290}
291
292impl CodeSuggestion {
293 pub(crate) fn splice_lines(
296 &self,
297 sm: &SourceMap,
298 ) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, bool)> {
299 use rustc_span::{CharPos, Pos};
304
305 fn push_trailing(
314 buf: &mut String,
315 line_opt: Option<&Cow<'_, str>>,
316 lo: &Loc,
317 hi_opt: Option<&Loc>,
318 ) -> usize {
319 let mut line_count = 0;
320 let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
323 if let Some(line) = line_opt {
324 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
325 let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
327 match hi_opt {
328 Some(hi) if hi > lo => {
330 line_count = line[lo..hi].matches('\n').count();
332 buf.push_str(&line[lo..hi])
333 }
334 Some(_) => (),
335 None => {
337 line_count = line[lo..].matches('\n').count();
339 buf.push_str(&line[lo..])
340 }
341 }
342 }
343 if hi_opt.is_none() {
345 buf.push('\n');
346 }
347 }
348 line_count
349 }
350
351 assert!(!self.substitutions.is_empty());
352
353 self.substitutions
354 .iter()
355 .filter(|subst| {
356 let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
359 if invalid {
360 debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
361 }
362 !invalid
363 })
364 .cloned()
365 .filter_map(|mut substitution| {
366 substitution.parts.sort_by_key(|part| part.span.lo());
369
370 let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
372 let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
373 let bounding_span = Span::with_root_ctxt(lo, hi);
374 let lines = sm.span_to_lines(bounding_span).ok()?;
376 assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
377
378 if !sm.ensure_source_file_source_present(&lines.file) {
380 return None;
381 }
382
383 let mut highlights = vec![];
384 let sf = &lines.file;
394 let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
395 prev_hi.col = CharPos::from_usize(0);
396 let mut prev_line =
397 lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
398 let mut buf = String::new();
399
400 let mut line_highlight = vec![];
401 let mut acc = 0;
404 let mut only_capitalization = false;
405 for part in &mut substitution.parts {
406 part.trim_trivial_replacements(sm);
410
411 only_capitalization |= is_case_difference(sm, &part.snippet, part.span);
412 let cur_lo = sm.lookup_char_pos(part.span.lo());
413 if prev_hi.line == cur_lo.line {
414 let mut count =
415 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
416 while count > 0 {
417 highlights.push(std::mem::take(&mut line_highlight));
418 acc = 0;
419 count -= 1;
420 }
421 } else {
422 acc = 0;
423 highlights.push(std::mem::take(&mut line_highlight));
424 let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
425 while count > 0 {
426 highlights.push(std::mem::take(&mut line_highlight));
427 count -= 1;
428 }
429 for idx in prev_hi.line..(cur_lo.line - 1) {
431 if let Some(line) = sf.get_line(idx) {
432 buf.push_str(line.as_ref());
433 buf.push('\n');
434 highlights.push(std::mem::take(&mut line_highlight));
435 }
436 }
437 if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
438 let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
439 Some((i, _)) => i,
440 None => cur_line.len(),
441 };
442 buf.push_str(&cur_line[..end]);
443 }
444 }
445 let len: isize = part
447 .snippet
448 .split('\n')
449 .next()
450 .unwrap_or(&part.snippet)
451 .chars()
452 .map(|c| match c {
453 '\t' => 4,
454 _ => 1,
455 })
456 .sum();
457 if !is_different(sm, &part.snippet, part.span) {
458 } else {
462 line_highlight.push(SubstitutionHighlight {
463 start: (cur_lo.col.0 as isize + acc) as usize,
464 end: (cur_lo.col.0 as isize + acc + len) as usize,
465 });
466 }
467 buf.push_str(&part.snippet);
468 let cur_hi = sm.lookup_char_pos(part.span.hi());
469 acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
474 prev_hi = cur_hi;
475 prev_line = sf.get_line(prev_hi.line - 1);
476 for line in part.snippet.split('\n').skip(1) {
477 acc = 0;
478 highlights.push(std::mem::take(&mut line_highlight));
479 let end: usize = line
480 .chars()
481 .map(|c| match c {
482 '\t' => 4,
483 _ => 1,
484 })
485 .sum();
486 line_highlight.push(SubstitutionHighlight { start: 0, end });
487 }
488 }
489 highlights.push(std::mem::take(&mut line_highlight));
490 if !buf.ends_with('\n') {
492 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
493 }
494 while buf.ends_with('\n') {
496 buf.pop();
497 }
498 if highlights.iter().all(|parts| parts.is_empty()) {
499 None
500 } else {
501 Some((buf, substitution.parts, highlights, only_capitalization))
502 }
503 })
504 .collect()
505 }
506}
507
508pub struct ExplicitBug;
511
512pub struct DelayedBugPanic;
515
516pub struct DiagCtxt {
520 inner: Lock<DiagCtxtInner>,
521}
522
523#[derive(Copy, Clone)]
524pub struct DiagCtxtHandle<'a> {
525 dcx: &'a DiagCtxt,
526 tainted_with_errors: Option<&'a Cell<Option<ErrorGuaranteed>>>,
529}
530
531impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
532 type Target = &'a DiagCtxt;
533
534 fn deref(&self) -> &Self::Target {
535 &self.dcx
536 }
537}
538
539struct DiagCtxtInner {
543 flags: DiagCtxtFlags,
544
545 registry: Registry,
546
547 err_guars: Vec<ErrorGuaranteed>,
549 lint_err_guars: Vec<ErrorGuaranteed>,
552 delayed_bugs: Vec<(DelayedDiagInner, ErrorGuaranteed)>,
554
555 deduplicated_err_count: usize,
557 deduplicated_warn_count: usize,
559
560 emitter: Box<DynEmitter>,
561
562 must_produce_diag: Option<Backtrace>,
565
566 has_printed: bool,
569
570 suppressed_expected_diag: bool,
573
574 taught_diagnostics: FxHashSet<ErrCode>,
578
579 emitted_diagnostic_codes: FxIndexSet<ErrCode>,
581
582 emitted_diagnostics: FxHashSet<Hash128>,
586
587 stashed_diagnostics:
593 FxIndexMap<StashKey, FxIndexMap<Span, (DiagInner, Option<ErrorGuaranteed>)>>,
594
595 future_breakage_diagnostics: Vec<DiagInner>,
596
597 fulfilled_expectations: FxIndexSet<LintExpectationId>,
609
610 ice_file: Option<PathBuf>,
613}
614
615#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
617pub enum StashKey {
618 ItemNoType,
619 UnderscoreForArrayLengths,
620 EarlySyntaxWarning,
621 CallIntoMethod,
622 LifetimeIsChar,
625 MaybeFruTypo,
628 CallAssocMethod,
629 AssociatedTypeSuggestion,
630 Cycle,
632 UndeterminedMacroResolution,
633 ExprInPat,
635 GenericInFieldExpr,
639}
640
641fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
642 (*f)(diag)
643}
644
645pub static TRACK_DIAGNOSTIC: AtomicRef<
648 fn(DiagInner, &mut dyn FnMut(DiagInner) -> Option<ErrorGuaranteed>) -> Option<ErrorGuaranteed>,
649> = AtomicRef::new(&(default_track_diagnostic as _));
650
651#[derive(Copy, Clone, Default)]
652pub struct DiagCtxtFlags {
653 pub can_emit_warnings: bool,
656 pub treat_err_as_bug: Option<NonZero<usize>>,
659 pub eagerly_emit_delayed_bugs: bool,
662 pub macro_backtrace: bool,
665 pub deduplicate_diagnostics: bool,
667 pub track_diagnostics: bool,
669}
670
671impl Drop for DiagCtxtInner {
672 fn drop(&mut self) {
673 self.emit_stashed_diagnostics();
681
682 self.flush_delayed();
686
687 if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
691 if let Some(backtrace) = &self.must_produce_diag {
692 let suggestion = match backtrace.status() {
693 BacktraceStatus::Disabled => String::from(
694 "Backtraces are currently disabled: set `RUST_BACKTRACE=1` and re-run \
695 to see where it happened.",
696 ),
697 BacktraceStatus::Captured => format!(
698 "This happened in the following `must_produce_diag` call's backtrace:\n\
699 {backtrace}",
700 ),
701 _ => String::from("(impossible to capture backtrace where this happened)"),
702 };
703 panic!(
704 "`trimmed_def_paths` called, diagnostics were expected but none were emitted. \
705 Use `with_no_trimmed_paths` for debugging. {suggestion}"
706 );
707 }
708 }
709 }
710}
711
712impl DiagCtxt {
713 pub fn disable_warnings(mut self) -> Self {
714 self.inner.get_mut().flags.can_emit_warnings = false;
715 self
716 }
717
718 pub fn with_flags(mut self, flags: DiagCtxtFlags) -> Self {
719 self.inner.get_mut().flags = flags;
720 self
721 }
722
723 pub fn with_ice_file(mut self, ice_file: PathBuf) -> Self {
724 self.inner.get_mut().ice_file = Some(ice_file);
725 self
726 }
727
728 pub fn with_registry(mut self, registry: Registry) -> Self {
729 self.inner.get_mut().registry = registry;
730 self
731 }
732
733 pub fn new(emitter: Box<DynEmitter>) -> Self {
734 Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
735 }
736
737 pub fn make_silent(&self, fatal_note: Option<String>, emit_fatal_diagnostic: bool) {
738 struct FalseEmitter;
741
742 impl Emitter for FalseEmitter {
743 fn emit_diagnostic(&mut self, _: DiagInner, _: &Registry) {
744 unimplemented!("false emitter must only used during `make_silent`")
745 }
746
747 fn source_map(&self) -> Option<&SourceMap> {
748 unimplemented!("false emitter must only used during `make_silent`")
749 }
750 }
751
752 impl translation::Translate for FalseEmitter {
753 fn fluent_bundle(&self) -> Option<&FluentBundle> {
754 unimplemented!("false emitter must only used during `make_silent`")
755 }
756
757 fn fallback_fluent_bundle(&self) -> &FluentBundle {
758 unimplemented!("false emitter must only used during `make_silent`")
759 }
760 }
761
762 let mut inner = self.inner.borrow_mut();
763 let mut prev_emitter = Box::new(FalseEmitter) as Box<dyn Emitter + DynSend>;
764 std::mem::swap(&mut inner.emitter, &mut prev_emitter);
765 let new_emitter = Box::new(emitter::SilentEmitter {
766 fatal_emitter: prev_emitter,
767 fatal_note,
768 emit_fatal_diagnostic,
769 });
770 inner.emitter = new_emitter;
771 }
772
773 pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) {
774 self.inner.borrow_mut().emitter = emitter;
775 }
776
777 pub fn eagerly_translate<'a>(
779 &self,
780 message: DiagMessage,
781 args: impl Iterator<Item = DiagArg<'a>>,
782 ) -> SubdiagMessage {
783 let inner = self.inner.borrow();
784 inner.eagerly_translate(message, args)
785 }
786
787 pub fn eagerly_translate_to_string<'a>(
789 &self,
790 message: DiagMessage,
791 args: impl Iterator<Item = DiagArg<'a>>,
792 ) -> String {
793 let inner = self.inner.borrow();
794 inner.eagerly_translate_to_string(message, args)
795 }
796
797 pub fn can_emit_warnings(&self) -> bool {
801 self.inner.borrow_mut().flags.can_emit_warnings
802 }
803
804 pub fn reset_err_count(&self) {
810 let mut inner = self.inner.borrow_mut();
813 let DiagCtxtInner {
814 flags: _,
815 registry: _,
816 err_guars,
817 lint_err_guars,
818 delayed_bugs,
819 deduplicated_err_count,
820 deduplicated_warn_count,
821 emitter: _,
822 must_produce_diag,
823 has_printed,
824 suppressed_expected_diag,
825 taught_diagnostics,
826 emitted_diagnostic_codes,
827 emitted_diagnostics,
828 stashed_diagnostics,
829 future_breakage_diagnostics,
830 fulfilled_expectations,
831 ice_file: _,
832 } = inner.deref_mut();
833
834 *err_guars = Default::default();
837 *lint_err_guars = Default::default();
838 *delayed_bugs = Default::default();
839 *deduplicated_err_count = 0;
840 *deduplicated_warn_count = 0;
841 *must_produce_diag = None;
842 *has_printed = false;
843 *suppressed_expected_diag = false;
844 *taught_diagnostics = Default::default();
845 *emitted_diagnostic_codes = Default::default();
846 *emitted_diagnostics = Default::default();
847 *stashed_diagnostics = Default::default();
848 *future_breakage_diagnostics = Default::default();
849 *fulfilled_expectations = Default::default();
850 }
851
852 pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> {
853 DiagCtxtHandle { dcx: self, tainted_with_errors: None }
854 }
855
856 pub fn taintable_handle<'a>(
860 &'a self,
861 tainted_with_errors: &'a Cell<Option<ErrorGuaranteed>>,
862 ) -> DiagCtxtHandle<'a> {
863 DiagCtxtHandle { dcx: self, tainted_with_errors: Some(tainted_with_errors) }
864 }
865}
866
867impl<'a> DiagCtxtHandle<'a> {
868 pub fn stash_diagnostic(
890 &self,
891 span: Span,
892 key: StashKey,
893 diag: DiagInner,
894 ) -> Option<ErrorGuaranteed> {
895 let guar = match diag.level {
896 Bug | Fatal => {
897 self.span_bug(
898 span,
899 format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
900 );
901 }
902 Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
906 DelayedBug => {
907 return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors);
908 }
909 ForceWarning | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
910 | Expect => None,
911 };
912
913 self.inner
917 .borrow_mut()
918 .stashed_diagnostics
919 .entry(key)
920 .or_default()
921 .insert(span.with_parent(None), (diag, guar));
922
923 guar
924 }
925
926 pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
930 let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
932 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
933 )?;
934 assert!(!diag.is_error());
935 assert!(guar.is_none());
936 Some(Diag::new_diagnostic(self, diag))
937 }
938
939 pub fn try_steal_modify_and_emit_err<F>(
944 self,
945 span: Span,
946 key: StashKey,
947 mut modify_err: F,
948 ) -> Option<ErrorGuaranteed>
949 where
950 F: FnMut(&mut Diag<'_>),
951 {
952 let err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
954 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
955 );
956 err.map(|(err, guar)| {
957 assert_eq!(err.level, Error);
959 assert!(guar.is_some());
960 let mut err = Diag::<ErrorGuaranteed>::new_diagnostic(self, err);
961 modify_err(&mut err);
962 assert_eq!(err.level, Error);
963 err.emit()
964 })
965 }
966
967 pub fn try_steal_replace_and_emit_err(
971 self,
972 span: Span,
973 key: StashKey,
974 new_err: Diag<'_>,
975 ) -> ErrorGuaranteed {
976 let old_err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
978 |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
979 );
980 match old_err {
981 Some((old_err, guar)) => {
982 assert_eq!(old_err.level, Error);
983 assert!(guar.is_some());
984 Diag::<ErrorGuaranteed>::new_diagnostic(self, old_err).cancel();
987 }
988 None => {}
989 };
990 new_err.emit()
991 }
992
993 pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
994 let inner = self.inner.borrow();
995 if let Some(stashed_diagnostics) = inner.stashed_diagnostics.get(&key)
996 && !stashed_diagnostics.is_empty()
997 {
998 stashed_diagnostics.contains_key(&span.with_parent(None))
999 } else {
1000 false
1001 }
1002 }
1003
1004 pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
1006 self.inner.borrow_mut().emit_stashed_diagnostics()
1007 }
1008
1009 #[inline]
1011 pub fn err_count(&self) -> usize {
1012 let inner = self.inner.borrow();
1013 inner.err_guars.len()
1014 + inner.lint_err_guars.len()
1015 + inner
1016 .stashed_diagnostics
1017 .values()
1018 .map(|a| a.values().filter(|(_, guar)| guar.is_some()).count())
1019 .sum::<usize>()
1020 }
1021
1022 pub fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1025 self.inner.borrow().has_errors_excluding_lint_errors()
1026 }
1027
1028 pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
1030 self.inner.borrow().has_errors()
1031 }
1032
1033 pub fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1036 self.inner.borrow().has_errors_or_delayed_bugs()
1037 }
1038
1039 pub fn print_error_count(&self) {
1040 let mut inner = self.inner.borrow_mut();
1041
1042 assert!(inner.stashed_diagnostics.is_empty());
1045
1046 if inner.treat_err_as_bug() {
1047 return;
1048 }
1049
1050 let warnings = match inner.deduplicated_warn_count {
1051 0 => Cow::from(""),
1052 1 => Cow::from("1 warning emitted"),
1053 count => Cow::from(format!("{count} warnings emitted")),
1054 };
1055 let errors = match inner.deduplicated_err_count {
1056 0 => Cow::from(""),
1057 1 => Cow::from("aborting due to 1 previous error"),
1058 count => Cow::from(format!("aborting due to {count} previous errors")),
1059 };
1060
1061 match (errors.len(), warnings.len()) {
1062 (0, 0) => return,
1063 (0, _) => {
1064 inner.emit_diagnostic(
1067 DiagInner::new(ForceWarning, DiagMessage::Str(warnings)),
1068 None,
1069 );
1070 }
1071 (_, 0) => {
1072 inner.emit_diagnostic(DiagInner::new(Error, errors), self.tainted_with_errors);
1073 }
1074 (_, _) => {
1075 inner.emit_diagnostic(
1076 DiagInner::new(Error, format!("{errors}; {warnings}")),
1077 self.tainted_with_errors,
1078 );
1079 }
1080 }
1081
1082 let can_show_explain = inner.emitter.should_show_explain();
1083 let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty();
1084 if can_show_explain && are_there_diagnostics {
1085 let mut error_codes = inner
1086 .emitted_diagnostic_codes
1087 .iter()
1088 .filter_map(|&code| {
1089 if inner.registry.try_find_description(code).is_ok() {
1090 Some(code.to_string())
1091 } else {
1092 None
1093 }
1094 })
1095 .collect::<Vec<_>>();
1096 if !error_codes.is_empty() {
1097 error_codes.sort();
1098 if error_codes.len() > 1 {
1099 let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
1100 let msg1 = format!(
1101 "Some errors have detailed explanations: {}{}",
1102 error_codes[..limit].join(", "),
1103 if error_codes.len() > 9 { "..." } else { "." }
1104 );
1105 let msg2 = format!(
1106 "For more information about an error, try `rustc --explain {}`.",
1107 &error_codes[0]
1108 );
1109 inner.emit_diagnostic(DiagInner::new(FailureNote, msg1), None);
1110 inner.emit_diagnostic(DiagInner::new(FailureNote, msg2), None);
1111 } else {
1112 let msg = format!(
1113 "For more information about this error, try `rustc --explain {}`.",
1114 &error_codes[0]
1115 );
1116 inner.emit_diagnostic(DiagInner::new(FailureNote, msg), None);
1117 }
1118 }
1119 }
1120 }
1121
1122 pub fn abort_if_errors(&self) {
1127 if let Some(guar) = self.has_errors() {
1128 guar.raise_fatal();
1129 }
1130 }
1131
1132 pub fn must_teach(&self, code: ErrCode) -> bool {
1138 self.inner.borrow_mut().taught_diagnostics.insert(code)
1139 }
1140
1141 pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
1142 self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors)
1143 }
1144
1145 pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
1146 self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
1147 }
1148
1149 pub fn emit_future_breakage_report(&self) {
1150 let inner = &mut *self.inner.borrow_mut();
1151 let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
1152 if !diags.is_empty() {
1153 inner.emitter.emit_future_breakage_report(diags, &inner.registry);
1154 }
1155 }
1156
1157 pub fn emit_unused_externs(
1158 &self,
1159 lint_level: rustc_lint_defs::Level,
1160 loud: bool,
1161 unused_externs: &[&str],
1162 ) {
1163 let mut inner = self.inner.borrow_mut();
1164
1165 if loud && lint_level.is_error() {
1176 #[allow(deprecated)]
1179 inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
1180 inner.panic_if_treat_err_as_bug();
1181 }
1182
1183 inner.emitter.emit_unused_externs(lint_level, unused_externs)
1184 }
1185
1186 #[must_use]
1189 pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
1190 std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
1191 }
1192
1193 pub fn flush_delayed(&self) {
1194 self.inner.borrow_mut().flush_delayed();
1195 }
1196
1197 #[track_caller]
1200 pub fn set_must_produce_diag(&self) {
1201 assert!(
1202 self.inner.borrow().must_produce_diag.is_none(),
1203 "should only need to collect a backtrace once"
1204 );
1205 self.inner.borrow_mut().must_produce_diag = Some(Backtrace::capture());
1206 }
1207}
1208
1209impl<'a> DiagCtxtHandle<'a> {
1214 #[track_caller]
1217 pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> {
1218 Diag::new(self, Bug, msg.into())
1219 }
1220
1221 #[track_caller]
1224 pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
1225 self.struct_bug(msg).emit()
1226 }
1227
1228 #[track_caller]
1231 pub fn struct_span_bug(
1232 self,
1233 span: impl Into<MultiSpan>,
1234 msg: impl Into<Cow<'static, str>>,
1235 ) -> Diag<'a, BugAbort> {
1236 self.struct_bug(msg).with_span(span)
1237 }
1238
1239 #[track_caller]
1242 pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
1243 self.struct_span_bug(span, msg.into()).emit()
1244 }
1245
1246 #[track_caller]
1247 pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> {
1248 bug.into_diag(self, Bug)
1249 }
1250
1251 #[track_caller]
1252 pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! {
1253 self.create_bug(bug).emit()
1254 }
1255
1256 #[rustc_lint_diagnostics]
1257 #[track_caller]
1258 pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> {
1259 Diag::new(self, Fatal, msg)
1260 }
1261
1262 #[rustc_lint_diagnostics]
1263 #[track_caller]
1264 pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
1265 self.struct_fatal(msg).emit()
1266 }
1267
1268 #[rustc_lint_diagnostics]
1269 #[track_caller]
1270 pub fn struct_span_fatal(
1271 self,
1272 span: impl Into<MultiSpan>,
1273 msg: impl Into<DiagMessage>,
1274 ) -> Diag<'a, FatalAbort> {
1275 self.struct_fatal(msg).with_span(span)
1276 }
1277
1278 #[rustc_lint_diagnostics]
1279 #[track_caller]
1280 pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
1281 self.struct_span_fatal(span, msg).emit()
1282 }
1283
1284 #[track_caller]
1285 pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> {
1286 fatal.into_diag(self, Fatal)
1287 }
1288
1289 #[track_caller]
1290 pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
1291 self.create_fatal(fatal).emit()
1292 }
1293
1294 #[track_caller]
1295 pub fn create_almost_fatal(
1296 self,
1297 fatal: impl Diagnostic<'a, FatalError>,
1298 ) -> Diag<'a, FatalError> {
1299 fatal.into_diag(self, Fatal)
1300 }
1301
1302 #[track_caller]
1303 pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError {
1304 self.create_almost_fatal(fatal).emit()
1305 }
1306
1307 #[rustc_lint_diagnostics]
1309 #[track_caller]
1310 pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> {
1311 Diag::new(self, Error, msg)
1312 }
1313
1314 #[rustc_lint_diagnostics]
1315 #[track_caller]
1316 pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
1317 self.struct_err(msg).emit()
1318 }
1319
1320 #[rustc_lint_diagnostics]
1321 #[track_caller]
1322 pub fn struct_span_err(
1323 self,
1324 span: impl Into<MultiSpan>,
1325 msg: impl Into<DiagMessage>,
1326 ) -> Diag<'a> {
1327 self.struct_err(msg).with_span(span)
1328 }
1329
1330 #[rustc_lint_diagnostics]
1331 #[track_caller]
1332 pub fn span_err(
1333 self,
1334 span: impl Into<MultiSpan>,
1335 msg: impl Into<DiagMessage>,
1336 ) -> ErrorGuaranteed {
1337 self.struct_span_err(span, msg).emit()
1338 }
1339
1340 #[track_caller]
1341 pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> {
1342 err.into_diag(self, Error)
1343 }
1344
1345 #[track_caller]
1346 pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
1347 self.create_err(err).emit()
1348 }
1349
1350 #[track_caller]
1355 pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
1356 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
1357 }
1358
1359 #[track_caller]
1367 pub fn span_delayed_bug(
1368 self,
1369 sp: impl Into<MultiSpan>,
1370 msg: impl Into<Cow<'static, str>>,
1371 ) -> ErrorGuaranteed {
1372 Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
1373 }
1374
1375 #[rustc_lint_diagnostics]
1376 #[track_caller]
1377 pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1378 Diag::new(self, Warning, msg)
1379 }
1380
1381 #[rustc_lint_diagnostics]
1382 #[track_caller]
1383 pub fn warn(self, msg: impl Into<DiagMessage>) {
1384 self.struct_warn(msg).emit()
1385 }
1386
1387 #[rustc_lint_diagnostics]
1388 #[track_caller]
1389 pub fn struct_span_warn(
1390 self,
1391 span: impl Into<MultiSpan>,
1392 msg: impl Into<DiagMessage>,
1393 ) -> Diag<'a, ()> {
1394 self.struct_warn(msg).with_span(span)
1395 }
1396
1397 #[rustc_lint_diagnostics]
1398 #[track_caller]
1399 pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1400 self.struct_span_warn(span, msg).emit()
1401 }
1402
1403 #[track_caller]
1404 pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1405 warning.into_diag(self, Warning)
1406 }
1407
1408 #[track_caller]
1409 pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) {
1410 self.create_warn(warning).emit()
1411 }
1412
1413 #[rustc_lint_diagnostics]
1414 #[track_caller]
1415 pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1416 Diag::new(self, Note, msg)
1417 }
1418
1419 #[rustc_lint_diagnostics]
1420 #[track_caller]
1421 pub fn note(&self, msg: impl Into<DiagMessage>) {
1422 self.struct_note(msg).emit()
1423 }
1424
1425 #[rustc_lint_diagnostics]
1426 #[track_caller]
1427 pub fn struct_span_note(
1428 self,
1429 span: impl Into<MultiSpan>,
1430 msg: impl Into<DiagMessage>,
1431 ) -> Diag<'a, ()> {
1432 self.struct_note(msg).with_span(span)
1433 }
1434
1435 #[rustc_lint_diagnostics]
1436 #[track_caller]
1437 pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
1438 self.struct_span_note(span, msg).emit()
1439 }
1440
1441 #[track_caller]
1442 pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> {
1443 note.into_diag(self, Note)
1444 }
1445
1446 #[track_caller]
1447 pub fn emit_note(self, note: impl Diagnostic<'a, ()>) {
1448 self.create_note(note).emit()
1449 }
1450
1451 #[rustc_lint_diagnostics]
1452 #[track_caller]
1453 pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1454 Diag::new(self, Help, msg)
1455 }
1456
1457 #[rustc_lint_diagnostics]
1458 #[track_caller]
1459 pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1460 Diag::new(self, FailureNote, msg)
1461 }
1462
1463 #[rustc_lint_diagnostics]
1464 #[track_caller]
1465 pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
1466 Diag::new(self, Allow, msg)
1467 }
1468
1469 #[rustc_lint_diagnostics]
1470 #[track_caller]
1471 pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> {
1472 Diag::new(self, Expect, msg).with_lint_id(id)
1473 }
1474}
1475
1476impl DiagCtxtInner {
1481 fn new(emitter: Box<DynEmitter>) -> Self {
1482 Self {
1483 flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
1484 registry: Registry::new(&[]),
1485 err_guars: Vec::new(),
1486 lint_err_guars: Vec::new(),
1487 delayed_bugs: Vec::new(),
1488 deduplicated_err_count: 0,
1489 deduplicated_warn_count: 0,
1490 emitter,
1491 must_produce_diag: None,
1492 has_printed: false,
1493 suppressed_expected_diag: false,
1494 taught_diagnostics: Default::default(),
1495 emitted_diagnostic_codes: Default::default(),
1496 emitted_diagnostics: Default::default(),
1497 stashed_diagnostics: Default::default(),
1498 future_breakage_diagnostics: Vec::new(),
1499 fulfilled_expectations: Default::default(),
1500 ice_file: None,
1501 }
1502 }
1503
1504 fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
1506 let mut guar = None;
1507 let has_errors = !self.err_guars.is_empty();
1508 for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
1509 for (_, (diag, _guar)) in stashed_diagnostics {
1510 if !diag.is_error() {
1511 if !diag.is_force_warn() && has_errors {
1515 continue;
1516 }
1517 }
1518 guar = guar.or(self.emit_diagnostic(diag, None));
1519 }
1520 }
1521 guar
1522 }
1523
1524 fn emit_diagnostic(
1526 &mut self,
1527 mut diagnostic: DiagInner,
1528 taint: Option<&Cell<Option<ErrorGuaranteed>>>,
1529 ) -> Option<ErrorGuaranteed> {
1530 if diagnostic.has_future_breakage() {
1531 assert_matches!(diagnostic.level, Error | Warning | Allow | Expect);
1535 self.future_breakage_diagnostics.push(diagnostic.clone());
1536 }
1537
1538 match diagnostic.level {
1542 Bug => {}
1543 Fatal | Error => {
1544 if self.treat_next_err_as_bug() {
1545 diagnostic.level = Bug;
1547 }
1548 }
1549 DelayedBug => {
1550 if self.flags.eagerly_emit_delayed_bugs {
1555 if self.treat_next_err_as_bug() {
1557 diagnostic.level = Bug;
1558 } else {
1559 diagnostic.level = Error;
1560 }
1561 } else {
1562 return if let Some(guar) = self.has_errors() {
1565 Some(guar)
1566 } else {
1567 let backtrace = std::backtrace::Backtrace::capture();
1571 #[allow(deprecated)]
1575 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1576 self.delayed_bugs
1577 .push((DelayedDiagInner::with_backtrace(diagnostic, backtrace), guar));
1578 Some(guar)
1579 };
1580 }
1581 }
1582 ForceWarning if diagnostic.lint_id.is_none() => {} Warning => {
1584 if !self.flags.can_emit_warnings {
1585 if diagnostic.has_future_breakage() {
1587 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1589 }
1590 return None;
1591 }
1592 }
1593 Note | Help | FailureNote => {}
1594 OnceNote | OnceHelp => panic!("bad level: {:?}", diagnostic.level),
1595 Allow => {
1596 if diagnostic.has_future_breakage() {
1598 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1600 self.suppressed_expected_diag = true;
1601 }
1602 return None;
1603 }
1604 Expect | ForceWarning => {
1605 self.fulfilled_expectations.insert(diagnostic.lint_id.unwrap());
1606 if let Expect = diagnostic.level {
1607 TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
1609 self.suppressed_expected_diag = true;
1610 return None;
1611 }
1612 }
1613 }
1614
1615 TRACK_DIAGNOSTIC(diagnostic, &mut |mut diagnostic| {
1616 if let Some(code) = diagnostic.code {
1617 self.emitted_diagnostic_codes.insert(code);
1618 }
1619
1620 let already_emitted = {
1621 let mut hasher = StableHasher::new();
1622 diagnostic.hash(&mut hasher);
1623 let diagnostic_hash = hasher.finish();
1624 !self.emitted_diagnostics.insert(diagnostic_hash)
1625 };
1626
1627 let is_error = diagnostic.is_error();
1628 let is_lint = diagnostic.is_lint.is_some();
1629
1630 if !(self.flags.deduplicate_diagnostics && already_emitted) {
1633 debug!(?diagnostic);
1634 debug!(?self.emitted_diagnostics);
1635
1636 let not_yet_emitted = |sub: &mut Subdiag| {
1637 debug!(?sub);
1638 if sub.level != OnceNote && sub.level != OnceHelp {
1639 return true;
1640 }
1641 let mut hasher = StableHasher::new();
1642 sub.hash(&mut hasher);
1643 let diagnostic_hash = hasher.finish();
1644 debug!(?diagnostic_hash);
1645 self.emitted_diagnostics.insert(diagnostic_hash)
1646 };
1647 diagnostic.children.retain_mut(not_yet_emitted);
1648 if already_emitted {
1649 let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`";
1650 diagnostic.sub(Note, msg, MultiSpan::new());
1651 }
1652
1653 if is_error {
1654 self.deduplicated_err_count += 1;
1655 } else if matches!(diagnostic.level, ForceWarning | Warning) {
1656 self.deduplicated_warn_count += 1;
1657 }
1658 self.has_printed = true;
1659
1660 self.emitter.emit_diagnostic(diagnostic, &self.registry);
1661 }
1662
1663 if is_error {
1664 if !self.delayed_bugs.is_empty() {
1669 assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0);
1670 self.delayed_bugs.clear();
1671 self.delayed_bugs.shrink_to_fit();
1672 }
1673
1674 #[allow(deprecated)]
1677 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
1678 if is_lint {
1679 self.lint_err_guars.push(guar);
1680 } else {
1681 if let Some(taint) = taint {
1682 taint.set(Some(guar));
1683 }
1684 self.err_guars.push(guar);
1685 }
1686 self.panic_if_treat_err_as_bug();
1687 Some(guar)
1688 } else {
1689 None
1690 }
1691 })
1692 }
1693
1694 fn treat_err_as_bug(&self) -> bool {
1695 self.flags
1696 .treat_err_as_bug
1697 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
1698 }
1699
1700 fn treat_next_err_as_bug(&self) -> bool {
1702 self.flags
1703 .treat_err_as_bug
1704 .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
1705 }
1706
1707 fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
1708 self.err_guars.get(0).copied().or_else(|| {
1709 if let Some((_diag, guar)) = self
1710 .stashed_diagnostics
1711 .values()
1712 .flat_map(|stashed_diagnostics| stashed_diagnostics.values())
1713 .find(|(diag, guar)| guar.is_some() && diag.is_lint.is_none())
1714 {
1715 *guar
1716 } else {
1717 None
1718 }
1719 })
1720 }
1721
1722 fn has_errors(&self) -> Option<ErrorGuaranteed> {
1723 self.err_guars.get(0).copied().or_else(|| self.lint_err_guars.get(0).copied()).or_else(
1724 || {
1725 self.stashed_diagnostics.values().find_map(|stashed_diagnostics| {
1726 stashed_diagnostics.values().find_map(|(_, guar)| *guar)
1727 })
1728 },
1729 )
1730 }
1731
1732 fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
1733 self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
1734 }
1735
1736 fn eagerly_translate<'a>(
1738 &self,
1739 message: DiagMessage,
1740 args: impl Iterator<Item = DiagArg<'a>>,
1741 ) -> SubdiagMessage {
1742 SubdiagMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
1743 }
1744
1745 fn eagerly_translate_to_string<'a>(
1747 &self,
1748 message: DiagMessage,
1749 args: impl Iterator<Item = DiagArg<'a>>,
1750 ) -> String {
1751 let args = crate::translation::to_fluent_args(args);
1752 self.emitter.translate_message(&message, &args).map_err(Report::new).unwrap().to_string()
1753 }
1754
1755 fn eagerly_translate_for_subdiag(
1756 &self,
1757 diag: &DiagInner,
1758 msg: impl Into<SubdiagMessage>,
1759 ) -> SubdiagMessage {
1760 let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
1761 self.eagerly_translate(msg, diag.args.iter())
1762 }
1763
1764 fn flush_delayed(&mut self) {
1765 assert!(self.stashed_diagnostics.is_empty());
1769
1770 if !self.err_guars.is_empty() {
1771 return;
1773 }
1774
1775 if self.delayed_bugs.is_empty() {
1776 return;
1778 }
1779
1780 let bugs: Vec<_> =
1781 std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
1782
1783 let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0"));
1784 let decorate = backtrace || self.ice_file.is_none();
1785 let mut out = self
1786 .ice_file
1787 .as_ref()
1788 .and_then(|file| std::fs::File::options().create(true).append(true).open(file).ok());
1789
1790 let note1 = "no errors encountered even though delayed bugs were created";
1795 let note2 = "those delayed bugs will now be shown as internal compiler errors";
1796 self.emit_diagnostic(DiagInner::new(Note, note1), None);
1797 self.emit_diagnostic(DiagInner::new(Note, note2), None);
1798
1799 for bug in bugs {
1800 if let Some(out) = &mut out {
1801 _ = write!(
1802 out,
1803 "delayed bug: {}\n{}\n",
1804 bug.inner
1805 .messages
1806 .iter()
1807 .filter_map(|(msg, _)| msg.as_str())
1808 .collect::<String>(),
1809 &bug.note
1810 );
1811 }
1812
1813 let mut bug = if decorate { bug.decorate(self) } else { bug.inner };
1814
1815 if bug.level != DelayedBug {
1817 bug.arg("level", bug.level);
1824 let msg = crate::fluent_generated::errors_invalid_flushed_delayed_diagnostic_level;
1825 let msg = self.eagerly_translate_for_subdiag(&bug, msg); bug.sub(Note, msg, bug.span.primary_span().unwrap().into());
1827 }
1828 bug.level = Bug;
1829
1830 self.emit_diagnostic(bug, None);
1831 }
1832
1833 panic::panic_any(DelayedBugPanic);
1835 }
1836
1837 fn panic_if_treat_err_as_bug(&self) {
1838 if self.treat_err_as_bug() {
1839 let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
1840 assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
1841 if n == 1 {
1842 panic!("aborting due to `-Z treat-err-as-bug=1`");
1843 } else {
1844 panic!("aborting after {n} errors due to `-Z treat-err-as-bug={n}`");
1845 }
1846 }
1847 }
1848}
1849
1850struct DelayedDiagInner {
1851 inner: DiagInner,
1852 note: Backtrace,
1853}
1854
1855impl DelayedDiagInner {
1856 fn with_backtrace(diagnostic: DiagInner, backtrace: Backtrace) -> Self {
1857 DelayedDiagInner { inner: diagnostic, note: backtrace }
1858 }
1859
1860 fn decorate(self, dcx: &DiagCtxtInner) -> DiagInner {
1861 let mut diag = self.inner;
1865 let msg = match self.note.status() {
1866 BacktraceStatus::Captured => crate::fluent_generated::errors_delayed_at_with_newline,
1867 _ => crate::fluent_generated::errors_delayed_at_without_newline,
1870 };
1871 diag.arg("emitted_at", diag.emitted_at.clone());
1872 diag.arg("note", self.note);
1873 let msg = dcx.eagerly_translate_for_subdiag(&diag, msg); diag.sub(Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into());
1875 diag
1876 }
1877}
1878
1879#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
1899pub enum Level {
1900 Bug,
1902
1903 Fatal,
1906
1907 Error,
1910
1911 DelayedBug,
1916
1917 ForceWarning,
1923
1924 Warning,
1927
1928 Note,
1930
1931 OnceNote,
1933
1934 Help,
1936
1937 OnceHelp,
1939
1940 FailureNote,
1943
1944 Allow,
1946
1947 Expect,
1949}
1950
1951impl fmt::Display for Level {
1952 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1953 self.to_str().fmt(f)
1954 }
1955}
1956
1957impl Level {
1958 fn color(self) -> ColorSpec {
1959 let mut spec = ColorSpec::new();
1960 match self {
1961 Bug | Fatal | Error | DelayedBug => {
1962 spec.set_fg(Some(Color::Red)).set_intense(true);
1963 }
1964 ForceWarning | Warning => {
1965 spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
1966 }
1967 Note | OnceNote => {
1968 spec.set_fg(Some(Color::Green)).set_intense(true);
1969 }
1970 Help | OnceHelp => {
1971 spec.set_fg(Some(Color::Cyan)).set_intense(true);
1972 }
1973 FailureNote => {}
1974 Allow | Expect => unreachable!(),
1975 }
1976 spec
1977 }
1978
1979 pub fn to_str(self) -> &'static str {
1980 match self {
1981 Bug | DelayedBug => "error: internal compiler error",
1982 Fatal | Error => "error",
1983 ForceWarning | Warning => "warning",
1984 Note | OnceNote => "note",
1985 Help | OnceHelp => "help",
1986 FailureNote => "failure-note",
1987 Allow | Expect => unreachable!(),
1988 }
1989 }
1990
1991 pub fn is_failure_note(&self) -> bool {
1992 matches!(*self, FailureNote)
1993 }
1994
1995 fn can_be_subdiag(&self) -> bool {
1997 match self {
1998 Bug | DelayedBug | Fatal | Error | ForceWarning | FailureNote | Allow | Expect => false,
1999
2000 Warning | Note | Help | OnceNote | OnceHelp => true,
2001 }
2002 }
2003}
2004
2005pub fn elided_lifetime_in_path_suggestion(
2007 source_map: &SourceMap,
2008 n: usize,
2009 path_span: Span,
2010 incl_angl_brckt: bool,
2011 insertion_span: Span,
2012) -> ElidedLifetimeInPathSubdiag {
2013 let expected = ExpectedLifetimeParameter { span: path_span, count: n };
2014 let indicate = source_map.is_span_accessible(insertion_span).then(|| {
2016 let anon_lts = vec!["'_"; n].join(", ");
2017 let suggestion =
2018 if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
2019
2020 IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion }
2021 });
2022
2023 ElidedLifetimeInPathSubdiag { expected, indicate }
2024}
2025
2026pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
2027 diag: &mut Diag<'a, G>,
2028 ambiguity: rustc_lint_defs::AmbiguityErrorDiag,
2029) {
2030 diag.span_label(ambiguity.label_span, ambiguity.label_msg);
2031 diag.note(ambiguity.note_msg);
2032 diag.span_note(ambiguity.b1_span, ambiguity.b1_note_msg);
2033 for help_msg in ambiguity.b1_help_msgs {
2034 diag.help(help_msg);
2035 }
2036 diag.span_note(ambiguity.b2_span, ambiguity.b2_note_msg);
2037 for help_msg in ambiguity.b2_help_msgs {
2038 diag.help(help_msg);
2039 }
2040}
2041
2042pub fn a_or_an(s: &str) -> &'static str {
2046 let mut chars = s.chars();
2047 let Some(mut first_alpha_char) = chars.next() else {
2048 return "a";
2049 };
2050 if first_alpha_char == '`' {
2051 let Some(next) = chars.next() else {
2052 return "a";
2053 };
2054 first_alpha_char = next;
2055 }
2056 if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) {
2057 "an"
2058 } else {
2059 "a"
2060 }
2061}
2062
2063#[derive(Clone, Copy, PartialEq, Hash, Debug)]
2064pub enum TerminalUrl {
2065 No,
2066 Yes,
2067 Auto,
2068}