• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Diagnostics creation and emission for `rustc`.
2 //!
3 //! This module contains the code for creating and emitting diagnostics.
4 
5 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
6 #![feature(array_windows)]
7 #![feature(extract_if)]
8 #![feature(if_let_guard)]
9 #![feature(let_chains)]
10 #![feature(never_type)]
11 #![feature(result_option_inspect)]
12 #![feature(rustc_attrs)]
13 #![feature(yeet_expr)]
14 #![feature(try_blocks)]
15 #![feature(box_patterns)]
16 #![feature(error_reporter)]
17 #![allow(incomplete_features)]
18 
19 #[macro_use]
20 extern crate rustc_macros;
21 
22 #[macro_use]
23 extern crate tracing;
24 
25 pub use emitter::ColorConfig;
26 
27 use rustc_lint_defs::LintExpectationId;
28 use Level::*;
29 
30 use emitter::{is_case_difference, Emitter, EmitterWriter};
31 use registry::Registry;
32 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
33 use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
34 use rustc_data_structures::sync::{self, IntoDynSyncSend, Lock, Lrc};
35 use rustc_data_structures::AtomicRef;
36 pub use rustc_error_messages::{
37     fallback_fluent_bundle, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle,
38     LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage,
39 };
40 use rustc_fluent_macro::fluent_messages;
41 pub use rustc_lint_defs::{pluralize, Applicability};
42 use rustc_span::source_map::SourceMap;
43 pub use rustc_span::ErrorGuaranteed;
44 use rustc_span::{Loc, Span};
45 
46 use std::borrow::Cow;
47 use std::error::Report;
48 use std::fmt;
49 use std::hash::Hash;
50 use std::num::NonZeroUsize;
51 use std::panic;
52 use std::path::Path;
53 
54 use termcolor::{Color, ColorSpec};
55 
56 pub mod annotate_snippet_emitter_writer;
57 mod diagnostic;
58 mod diagnostic_builder;
59 mod diagnostic_impls;
60 pub mod emitter;
61 pub mod error;
62 pub mod json;
63 mod lock;
64 pub mod markdown;
65 pub mod registry;
66 mod snippet;
67 mod styled_buffer;
68 #[cfg(test)]
69 mod tests;
70 pub mod translation;
71 
72 pub use diagnostic_builder::IntoDiagnostic;
73 pub use snippet::Style;
74 
75 pub type PErr<'a> = DiagnosticBuilder<'a, ErrorGuaranteed>;
76 pub type PResult<'a, T> = Result<T, PErr<'a>>;
77 
78 fluent_messages! { "../messages.ftl" }
79 
80 // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
81 // (See also the comment on `DiagnosticBuilderInner`'s `diagnostic` field.)
82 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
83 rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16);
84 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
85 rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
86 
87 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
88 pub enum SuggestionStyle {
89     /// Hide the suggested code when displaying this suggestion inline.
90     HideCodeInline,
91     /// Always hide the suggested code but display the message.
92     HideCodeAlways,
93     /// Do not display this suggestion in the cli output, it is only meant for tools.
94     CompletelyHidden,
95     /// Always show the suggested code.
96     /// This will *not* show the code if the suggestion is inline *and* the suggested code is
97     /// empty.
98     ShowCode,
99     /// Always show the suggested code independently.
100     ShowAlways,
101 }
102 
103 impl SuggestionStyle {
hide_inline(&self) -> bool104     fn hide_inline(&self) -> bool {
105         !matches!(*self, SuggestionStyle::ShowCode)
106     }
107 }
108 
109 #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
110 pub struct CodeSuggestion {
111     /// Each substitute can have multiple variants due to multiple
112     /// applicable suggestions
113     ///
114     /// `foo.bar` might be replaced with `a.b` or `x.y` by replacing
115     /// `foo` and `bar` on their own:
116     ///
117     /// ```ignore (illustrative)
118     /// vec![
119     ///     Substitution { parts: vec![(0..3, "a"), (4..7, "b")] },
120     ///     Substitution { parts: vec![(0..3, "x"), (4..7, "y")] },
121     /// ]
122     /// ```
123     ///
124     /// or by replacing the entire span:
125     ///
126     /// ```ignore (illustrative)
127     /// vec![
128     ///     Substitution { parts: vec![(0..7, "a.b")] },
129     ///     Substitution { parts: vec![(0..7, "x.y")] },
130     /// ]
131     /// ```
132     pub substitutions: Vec<Substitution>,
133     pub msg: DiagnosticMessage,
134     /// Visual representation of this suggestion.
135     pub style: SuggestionStyle,
136     /// Whether or not the suggestion is approximate
137     ///
138     /// Sometimes we may show suggestions with placeholders,
139     /// which are useful for users but not useful for
140     /// tools like rustfix
141     pub applicability: Applicability,
142 }
143 
144 #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
145 /// See the docs on `CodeSuggestion::substitutions`
146 pub struct Substitution {
147     pub parts: Vec<SubstitutionPart>,
148 }
149 
150 #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
151 pub struct SubstitutionPart {
152     pub span: Span,
153     pub snippet: String,
154 }
155 
156 /// Used to translate between `Span`s and byte positions within a single output line in highlighted
157 /// code of structured suggestions.
158 #[derive(Debug, Clone, Copy)]
159 pub struct SubstitutionHighlight {
160     start: usize,
161     end: usize,
162 }
163 
164 impl SubstitutionPart {
is_addition(&self, sm: &SourceMap) -> bool165     pub fn is_addition(&self, sm: &SourceMap) -> bool {
166         !self.snippet.is_empty() && !self.replaces_meaningful_content(sm)
167     }
168 
is_deletion(&self, sm: &SourceMap) -> bool169     pub fn is_deletion(&self, sm: &SourceMap) -> bool {
170         self.snippet.trim().is_empty() && self.replaces_meaningful_content(sm)
171     }
172 
is_replacement(&self, sm: &SourceMap) -> bool173     pub fn is_replacement(&self, sm: &SourceMap) -> bool {
174         !self.snippet.is_empty() && self.replaces_meaningful_content(sm)
175     }
176 
replaces_meaningful_content(&self, sm: &SourceMap) -> bool177     fn replaces_meaningful_content(&self, sm: &SourceMap) -> bool {
178         sm.span_to_snippet(self.span)
179             .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty())
180     }
181 }
182 
183 impl CodeSuggestion {
184     /// Returns the assembled code suggestions, whether they should be shown with an underline
185     /// and whether the substitution only differs in capitalization.
splice_lines( &self, sm: &SourceMap, ) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, bool)>186     pub fn splice_lines(
187         &self,
188         sm: &SourceMap,
189     ) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, bool)> {
190         // For the `Vec<Vec<SubstitutionHighlight>>` value, the first level of the vector
191         // corresponds to the output snippet's lines, while the second level corresponds to the
192         // substrings within that line that should be highlighted.
193 
194         use rustc_span::{CharPos, Pos};
195 
196         /// Append to a buffer the remainder of the line of existing source code, and return the
197         /// count of lines that have been added for accurate highlighting.
198         fn push_trailing(
199             buf: &mut String,
200             line_opt: Option<&Cow<'_, str>>,
201             lo: &Loc,
202             hi_opt: Option<&Loc>,
203         ) -> usize {
204             let mut line_count = 0;
205             let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
206             if let Some(line) = line_opt {
207                 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
208                     let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
209                     match hi_opt {
210                         Some(hi) if hi > lo => {
211                             line_count = line[lo..hi].matches('\n').count();
212                             buf.push_str(&line[lo..hi])
213                         }
214                         Some(_) => (),
215                         None => {
216                             line_count = line[lo..].matches('\n').count();
217                             buf.push_str(&line[lo..])
218                         }
219                     }
220                 }
221                 if hi_opt.is_none() {
222                     buf.push('\n');
223                 }
224             }
225             line_count
226         }
227 
228         assert!(!self.substitutions.is_empty());
229 
230         self.substitutions
231             .iter()
232             .filter(|subst| {
233                 // Suggestions coming from macros can have malformed spans. This is a heavy
234                 // handed approach to avoid ICEs by ignoring the suggestion outright.
235                 let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
236                 if invalid {
237                     debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
238                 }
239                 !invalid
240             })
241             .cloned()
242             .filter_map(|mut substitution| {
243                 // Assumption: all spans are in the same file, and all spans
244                 // are disjoint. Sort in ascending order.
245                 substitution.parts.sort_by_key(|part| part.span.lo());
246 
247                 // Find the bounding span.
248                 let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
249                 let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
250                 let bounding_span = Span::with_root_ctxt(lo, hi);
251                 // The different spans might belong to different contexts, if so ignore suggestion.
252                 let lines = sm.span_to_lines(bounding_span).ok()?;
253                 assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
254 
255                 // We can't splice anything if the source is unavailable.
256                 if !sm.ensure_source_file_source_present(lines.file.clone()) {
257                     return None;
258                 }
259 
260                 let mut highlights = vec![];
261                 // To build up the result, we do this for each span:
262                 // - push the line segment trailing the previous span
263                 //   (at the beginning a "phantom" span pointing at the start of the line)
264                 // - push lines between the previous and current span (if any)
265                 // - if the previous and current span are not on the same line
266                 //   push the line segment leading up to the current span
267                 // - splice in the span substitution
268                 //
269                 // Finally push the trailing line segment of the last span
270                 let sf = &lines.file;
271                 let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
272                 prev_hi.col = CharPos::from_usize(0);
273                 let mut prev_line =
274                     lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
275                 let mut buf = String::new();
276 
277                 let mut line_highlight = vec![];
278                 // We need to keep track of the difference between the existing code and the added
279                 // or deleted code in order to point at the correct column *after* substitution.
280                 let mut acc = 0;
281                 for part in &substitution.parts {
282                     let cur_lo = sm.lookup_char_pos(part.span.lo());
283                     if prev_hi.line == cur_lo.line {
284                         let mut count =
285                             push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
286                         while count > 0 {
287                             highlights.push(std::mem::take(&mut line_highlight));
288                             acc = 0;
289                             count -= 1;
290                         }
291                     } else {
292                         acc = 0;
293                         highlights.push(std::mem::take(&mut line_highlight));
294                         let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
295                         while count > 0 {
296                             highlights.push(std::mem::take(&mut line_highlight));
297                             count -= 1;
298                         }
299                         // push lines between the previous and current span (if any)
300                         for idx in prev_hi.line..(cur_lo.line - 1) {
301                             if let Some(line) = sf.get_line(idx) {
302                                 buf.push_str(line.as_ref());
303                                 buf.push('\n');
304                                 highlights.push(std::mem::take(&mut line_highlight));
305                             }
306                         }
307                         if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
308                             let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
309                                 Some((i, _)) => i,
310                                 None => cur_line.len(),
311                             };
312                             buf.push_str(&cur_line[..end]);
313                         }
314                     }
315                     // Add a whole line highlight per line in the snippet.
316                     let len: isize = part
317                         .snippet
318                         .split('\n')
319                         .next()
320                         .unwrap_or(&part.snippet)
321                         .chars()
322                         .map(|c| match c {
323                             '\t' => 4,
324                             _ => 1,
325                         })
326                         .sum();
327                     line_highlight.push(SubstitutionHighlight {
328                         start: (cur_lo.col.0 as isize + acc) as usize,
329                         end: (cur_lo.col.0 as isize + acc + len) as usize,
330                     });
331                     buf.push_str(&part.snippet);
332                     let cur_hi = sm.lookup_char_pos(part.span.hi());
333                     // Account for the difference between the width of the current code and the
334                     // snippet being suggested, so that the *later* suggestions are correctly
335                     // aligned on the screen. Note that cur_hi and cur_lo can be on different
336                     // lines, so cur_hi.col can be smaller than cur_lo.col
337                     acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
338                     prev_hi = cur_hi;
339                     prev_line = sf.get_line(prev_hi.line - 1);
340                     for line in part.snippet.split('\n').skip(1) {
341                         acc = 0;
342                         highlights.push(std::mem::take(&mut line_highlight));
343                         let end: usize = line
344                             .chars()
345                             .map(|c| match c {
346                                 '\t' => 4,
347                                 _ => 1,
348                             })
349                             .sum();
350                         line_highlight.push(SubstitutionHighlight { start: 0, end });
351                     }
352                 }
353                 highlights.push(std::mem::take(&mut line_highlight));
354                 let only_capitalization = is_case_difference(sm, &buf, bounding_span);
355                 // if the replacement already ends with a newline, don't print the next line
356                 if !buf.ends_with('\n') {
357                     push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
358                 }
359                 // remove trailing newlines
360                 while buf.ends_with('\n') {
361                     buf.pop();
362                 }
363                 Some((buf, substitution.parts, highlights, only_capitalization))
364             })
365             .collect()
366     }
367 }
368 
369 pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
370 
371 /// Signifies that the compiler died with an explicit call to `.bug`
372 /// or `.span_bug` rather than a failed assertion, etc.
373 pub struct ExplicitBug;
374 
375 /// Signifies that the compiler died with an explicit call to `.delay_*_bug`
376 /// rather than a failed assertion, etc.
377 pub struct DelayedBugPanic;
378 
379 pub use diagnostic::{
380     AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId,
381     DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
382 };
383 pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted};
384 pub use diagnostic_impls::{
385     DiagnosticArgFromDisplay, DiagnosticSymbolList, LabelKind, SingleLabelManySpans,
386 };
387 use std::backtrace::{Backtrace, BacktraceStatus};
388 
389 /// A handler deals with errors and other compiler output.
390 /// Certain errors (fatal, bug, unimpl) may cause immediate exit,
391 /// others log errors for later reporting.
392 pub struct Handler {
393     flags: HandlerFlags,
394     inner: Lock<HandlerInner>,
395 }
396 
397 /// This inner struct exists to keep it all behind a single lock;
398 /// this is done to prevent possible deadlocks in a multi-threaded compiler,
399 /// as well as inconsistent state observation.
400 struct HandlerInner {
401     flags: HandlerFlags,
402     /// The number of lint errors that have been emitted.
403     lint_err_count: usize,
404     /// The number of errors that have been emitted, including duplicates.
405     ///
406     /// This is not necessarily the count that's reported to the user once
407     /// compilation ends.
408     err_count: usize,
409     warn_count: usize,
410     deduplicated_err_count: usize,
411     emitter: IntoDynSyncSend<Box<dyn Emitter + sync::Send>>,
412     delayed_span_bugs: Vec<DelayedDiagnostic>,
413     delayed_good_path_bugs: Vec<DelayedDiagnostic>,
414     /// This flag indicates that an expected diagnostic was emitted and suppressed.
415     /// This is used for the `delayed_good_path_bugs` check.
416     suppressed_expected_diag: bool,
417 
418     /// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
419     /// emitting the same diagnostic with extended help (`--teach`) twice, which
420     /// would be unnecessary repetition.
421     taught_diagnostics: FxHashSet<DiagnosticId>,
422 
423     /// Used to suggest rustc --explain `<error code>`
424     emitted_diagnostic_codes: FxIndexSet<DiagnosticId>,
425 
426     /// This set contains a hash of every diagnostic that has been emitted by
427     /// this handler. These hashes is used to avoid emitting the same error
428     /// twice.
429     emitted_diagnostics: FxHashSet<Hash128>,
430 
431     /// Stashed diagnostics emitted in one stage of the compiler that may be
432     /// stolen by other stages (e.g. to improve them and add more information).
433     /// The stashed diagnostics count towards the total error count.
434     /// When `.abort_if_errors()` is called, these are also emitted.
435     stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>,
436 
437     /// The warning count, used for a recap upon finishing
438     deduplicated_warn_count: usize,
439 
440     future_breakage_diagnostics: Vec<Diagnostic>,
441 
442     /// The [`Self::unstable_expect_diagnostics`] should be empty when this struct is
443     /// dropped. However, it can have values if the compilation is stopped early
444     /// or is only partially executed. To avoid ICEs, like in rust#94953 we only
445     /// check if [`Self::unstable_expect_diagnostics`] is empty, if the expectation ids
446     /// have been converted.
447     check_unstable_expect_diagnostics: bool,
448 
449     /// Expected [`Diagnostic`][diagnostic::Diagnostic]s store a [`LintExpectationId`] as part of
450     /// the lint level. [`LintExpectationId`]s created early during the compilation
451     /// (before `HirId`s have been defined) are not stable and can therefore not be
452     /// stored on disk. This buffer stores these diagnostics until the ID has been
453     /// replaced by a stable [`LintExpectationId`]. The [`Diagnostic`][diagnostic::Diagnostic]s are the
454     /// submitted for storage and added to the list of fulfilled expectations.
455     unstable_expect_diagnostics: Vec<Diagnostic>,
456 
457     /// expected diagnostic will have the level `Expect` which additionally
458     /// carries the [`LintExpectationId`] of the expectation that can be
459     /// marked as fulfilled. This is a collection of all [`LintExpectationId`]s
460     /// that have been marked as fulfilled this way.
461     ///
462     /// [RFC-2383]: https://rust-lang.github.io/rfcs/2383-lint-reasons.html
463     fulfilled_expectations: FxHashSet<LintExpectationId>,
464 }
465 
466 /// A key denoting where from a diagnostic was stashed.
467 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
468 pub enum StashKey {
469     ItemNoType,
470     UnderscoreForArrayLengths,
471     EarlySyntaxWarning,
472     CallIntoMethod,
473     /// When an invalid lifetime e.g. `'2` should be reinterpreted
474     /// as a char literal in the parser
475     LifetimeIsChar,
476     /// Maybe there was a typo where a comma was forgotten before
477     /// FRU syntax
478     MaybeFruTypo,
479     CallAssocMethod,
480     TraitMissingMethod,
481     OpaqueHiddenTypeMismatch,
482 }
483 
default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic))484 fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
485     (*f)(d)
486 }
487 
488 pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&mut Diagnostic, &mut dyn FnMut(&mut Diagnostic))> =
489     AtomicRef::new(&(default_track_diagnostic as _));
490 
491 #[derive(Copy, Clone, Default)]
492 pub struct HandlerFlags {
493     /// If false, warning-level lints are suppressed.
494     /// (rustc: see `--allow warnings` and `--cap-lints`)
495     pub can_emit_warnings: bool,
496     /// If true, error-level diagnostics are upgraded to bug-level.
497     /// (rustc: see `-Z treat-err-as-bug`)
498     pub treat_err_as_bug: Option<NonZeroUsize>,
499     /// If true, immediately emit diagnostics that would otherwise be buffered.
500     /// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`)
501     pub dont_buffer_diagnostics: bool,
502     /// If true, immediately print bugs registered with `delay_span_bug`.
503     /// (rustc: see `-Z report-delayed-bugs`)
504     pub report_delayed_bugs: bool,
505     /// Show macro backtraces.
506     /// (rustc: see `-Z macro-backtrace`)
507     pub macro_backtrace: bool,
508     /// If true, identical diagnostics are reported only once.
509     pub deduplicate_diagnostics: bool,
510     /// Track where errors are created. Enabled with `-Ztrack-diagnostics`.
511     pub track_diagnostics: bool,
512 }
513 
514 impl Drop for HandlerInner {
drop(&mut self)515     fn drop(&mut self) {
516         self.emit_stashed_diagnostics();
517 
518         if !self.has_errors() {
519             let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new());
520             self.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued");
521         }
522 
523         // FIXME(eddyb) this explains what `delayed_good_path_bugs` are!
524         // They're `delayed_span_bugs` but for "require some diagnostic happened"
525         // instead of "require some error happened". Sadly that isn't ideal, as
526         // lints can be `#[allow]`'d, potentially leading to this triggering.
527         // Also, "good path" should be replaced with a better naming.
528         if !self.has_any_message() && !self.suppressed_expected_diag {
529             let bugs = std::mem::replace(&mut self.delayed_good_path_bugs, Vec::new());
530             self.flush_delayed(
531                 bugs,
532                 "no warnings or errors encountered even though `delayed_good_path_bugs` issued",
533             );
534         }
535 
536         if self.check_unstable_expect_diagnostics {
537             assert!(
538                 self.unstable_expect_diagnostics.is_empty(),
539                 "all diagnostics with unstable expectations should have been converted",
540             );
541         }
542     }
543 }
544 
545 impl Handler {
with_tty_emitter( color_config: ColorConfig, can_emit_warnings: bool, treat_err_as_bug: Option<NonZeroUsize>, sm: Option<Lrc<SourceMap>>, fluent_bundle: Option<Lrc<FluentBundle>>, fallback_bundle: LazyFallbackBundle, ) -> Self546     pub fn with_tty_emitter(
547         color_config: ColorConfig,
548         can_emit_warnings: bool,
549         treat_err_as_bug: Option<NonZeroUsize>,
550         sm: Option<Lrc<SourceMap>>,
551         fluent_bundle: Option<Lrc<FluentBundle>>,
552         fallback_bundle: LazyFallbackBundle,
553     ) -> Self {
554         Self::with_tty_emitter_and_flags(
555             color_config,
556             sm,
557             fluent_bundle,
558             fallback_bundle,
559             HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default::default() },
560         )
561     }
562 
with_tty_emitter_and_flags( color_config: ColorConfig, sm: Option<Lrc<SourceMap>>, fluent_bundle: Option<Lrc<FluentBundle>>, fallback_bundle: LazyFallbackBundle, flags: HandlerFlags, ) -> Self563     pub fn with_tty_emitter_and_flags(
564         color_config: ColorConfig,
565         sm: Option<Lrc<SourceMap>>,
566         fluent_bundle: Option<Lrc<FluentBundle>>,
567         fallback_bundle: LazyFallbackBundle,
568         flags: HandlerFlags,
569     ) -> Self {
570         let emitter = Box::new(EmitterWriter::stderr(
571             color_config,
572             sm,
573             fluent_bundle,
574             fallback_bundle,
575             false,
576             false,
577             None,
578             flags.macro_backtrace,
579             flags.track_diagnostics,
580             TerminalUrl::No,
581         ));
582         Self::with_emitter_and_flags(emitter, flags)
583     }
584 
with_emitter( can_emit_warnings: bool, treat_err_as_bug: Option<NonZeroUsize>, emitter: Box<dyn Emitter + sync::Send>, ) -> Self585     pub fn with_emitter(
586         can_emit_warnings: bool,
587         treat_err_as_bug: Option<NonZeroUsize>,
588         emitter: Box<dyn Emitter + sync::Send>,
589     ) -> Self {
590         Handler::with_emitter_and_flags(
591             emitter,
592             HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default::default() },
593         )
594     }
595 
with_emitter_and_flags( emitter: Box<dyn Emitter + sync::Send>, flags: HandlerFlags, ) -> Self596     pub fn with_emitter_and_flags(
597         emitter: Box<dyn Emitter + sync::Send>,
598         flags: HandlerFlags,
599     ) -> Self {
600         Self {
601             flags,
602             inner: Lock::new(HandlerInner {
603                 flags,
604                 lint_err_count: 0,
605                 err_count: 0,
606                 warn_count: 0,
607                 deduplicated_err_count: 0,
608                 deduplicated_warn_count: 0,
609                 emitter: IntoDynSyncSend(emitter),
610                 delayed_span_bugs: Vec::new(),
611                 delayed_good_path_bugs: Vec::new(),
612                 suppressed_expected_diag: false,
613                 taught_diagnostics: Default::default(),
614                 emitted_diagnostic_codes: Default::default(),
615                 emitted_diagnostics: Default::default(),
616                 stashed_diagnostics: Default::default(),
617                 future_breakage_diagnostics: Vec::new(),
618                 check_unstable_expect_diagnostics: false,
619                 unstable_expect_diagnostics: Vec::new(),
620                 fulfilled_expectations: Default::default(),
621             }),
622         }
623     }
624 
625     /// Translate `message` eagerly with `args` to `SubdiagnosticMessage::Eager`.
eagerly_translate<'a>( &self, message: DiagnosticMessage, args: impl Iterator<Item = DiagnosticArg<'a, 'static>>, ) -> SubdiagnosticMessage626     pub fn eagerly_translate<'a>(
627         &self,
628         message: DiagnosticMessage,
629         args: impl Iterator<Item = DiagnosticArg<'a, 'static>>,
630     ) -> SubdiagnosticMessage {
631         SubdiagnosticMessage::Eager(Cow::from(self.eagerly_translate_to_string(message, args)))
632     }
633 
634     /// Translate `message` eagerly with `args` to `String`.
eagerly_translate_to_string<'a>( &self, message: DiagnosticMessage, args: impl Iterator<Item = DiagnosticArg<'a, 'static>>, ) -> String635     pub fn eagerly_translate_to_string<'a>(
636         &self,
637         message: DiagnosticMessage,
638         args: impl Iterator<Item = DiagnosticArg<'a, 'static>>,
639     ) -> String {
640         let inner = self.inner.borrow();
641         let args = crate::translation::to_fluent_args(args);
642         inner.emitter.translate_message(&message, &args).map_err(Report::new).unwrap().to_string()
643     }
644 
645     // This is here to not allow mutation of flags;
646     // as of this writing it's only used in tests in librustc_middle.
can_emit_warnings(&self) -> bool647     pub fn can_emit_warnings(&self) -> bool {
648         self.flags.can_emit_warnings
649     }
650 
651     /// Resets the diagnostic error count as well as the cached emitted diagnostics.
652     ///
653     /// NOTE: *do not* call this function from rustc. It is only meant to be called from external
654     /// tools that want to reuse a `Parser` cleaning the previously emitted diagnostics as well as
655     /// the overall count of emitted error diagnostics.
reset_err_count(&self)656     pub fn reset_err_count(&self) {
657         let mut inner = self.inner.borrow_mut();
658         inner.err_count = 0;
659         inner.warn_count = 0;
660         inner.deduplicated_err_count = 0;
661         inner.deduplicated_warn_count = 0;
662 
663         // actually free the underlying memory (which `clear` would not do)
664         inner.delayed_span_bugs = Default::default();
665         inner.delayed_good_path_bugs = Default::default();
666         inner.taught_diagnostics = Default::default();
667         inner.emitted_diagnostic_codes = Default::default();
668         inner.emitted_diagnostics = Default::default();
669         inner.stashed_diagnostics = Default::default();
670     }
671 
672     /// Stash a given diagnostic with the given `Span` and [`StashKey`] as the key.
673     /// Retrieve a stashed diagnostic with `steal_diagnostic`.
stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic)674     pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
675         let mut inner = self.inner.borrow_mut();
676         inner.stash((span.with_parent(None), key), diag);
677     }
678 
679     /// Steal a previously stashed diagnostic with the given `Span` and [`StashKey`] as the key.
steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>>680     pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>> {
681         let mut inner = self.inner.borrow_mut();
682         inner
683             .steal((span.with_parent(None), key))
684             .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
685     }
686 
has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool687     pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
688         self.inner.borrow().stashed_diagnostics.get(&(span.with_parent(None), key)).is_some()
689     }
690 
691     /// Emit all stashed diagnostics.
emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed>692     pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
693         self.inner.borrow_mut().emit_stashed_diagnostics()
694     }
695 
696     /// Construct a builder with the `msg` at the level appropriate for the specific `EmissionGuarantee`.
697     #[rustc_lint_diagnostics]
698     #[track_caller]
struct_diagnostic<G: EmissionGuarantee>( &self, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, G>699     pub fn struct_diagnostic<G: EmissionGuarantee>(
700         &self,
701         msg: impl Into<DiagnosticMessage>,
702     ) -> DiagnosticBuilder<'_, G> {
703         G::make_diagnostic_builder(self, msg)
704     }
705 
706     /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
707     ///
708     /// Attempting to `.emit()` the builder will only emit if either:
709     /// * `can_emit_warnings` is `true`
710     /// * `is_force_warn` was set in `DiagnosticId::Lint`
711     #[rustc_lint_diagnostics]
712     #[track_caller]
struct_span_warn( &self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ()>713     pub fn struct_span_warn(
714         &self,
715         span: impl Into<MultiSpan>,
716         msg: impl Into<DiagnosticMessage>,
717     ) -> DiagnosticBuilder<'_, ()> {
718         let mut result = self.struct_warn(msg);
719         result.set_span(span);
720         result
721     }
722 
723     /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
724     /// The `id` is used for lint emissions which should also fulfill a lint expectation.
725     ///
726     /// Attempting to `.emit()` the builder will only emit if either:
727     /// * `can_emit_warnings` is `true`
728     /// * `is_force_warn` was set in `DiagnosticId::Lint`
729     #[track_caller]
struct_span_warn_with_expectation( &self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, id: LintExpectationId, ) -> DiagnosticBuilder<'_, ()>730     pub fn struct_span_warn_with_expectation(
731         &self,
732         span: impl Into<MultiSpan>,
733         msg: impl Into<DiagnosticMessage>,
734         id: LintExpectationId,
735     ) -> DiagnosticBuilder<'_, ()> {
736         let mut result = self.struct_warn_with_expectation(msg, id);
737         result.set_span(span);
738         result
739     }
740 
741     /// Construct a builder at the `Allow` level at the given `span` and with the `msg`.
742     #[rustc_lint_diagnostics]
743     #[track_caller]
struct_span_allow( &self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ()>744     pub fn struct_span_allow(
745         &self,
746         span: impl Into<MultiSpan>,
747         msg: impl Into<DiagnosticMessage>,
748     ) -> DiagnosticBuilder<'_, ()> {
749         let mut result = self.struct_allow(msg);
750         result.set_span(span);
751         result
752     }
753 
754     /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
755     /// Also include a code.
756     #[rustc_lint_diagnostics]
757     #[track_caller]
struct_span_warn_with_code( &self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, ) -> DiagnosticBuilder<'_, ()>758     pub fn struct_span_warn_with_code(
759         &self,
760         span: impl Into<MultiSpan>,
761         msg: impl Into<DiagnosticMessage>,
762         code: DiagnosticId,
763     ) -> DiagnosticBuilder<'_, ()> {
764         let mut result = self.struct_span_warn(span, msg);
765         result.code(code);
766         result
767     }
768 
769     /// Construct a builder at the `Warning` level with the `msg`.
770     ///
771     /// Attempting to `.emit()` the builder will only emit if either:
772     /// * `can_emit_warnings` is `true`
773     /// * `is_force_warn` was set in `DiagnosticId::Lint`
774     #[rustc_lint_diagnostics]
775     #[track_caller]
struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()>776     pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
777         DiagnosticBuilder::new(self, Level::Warning(None), msg)
778     }
779 
780     /// Construct a builder at the `Warning` level with the `msg`. The `id` is used for
781     /// lint emissions which should also fulfill a lint expectation.
782     ///
783     /// Attempting to `.emit()` the builder will only emit if either:
784     /// * `can_emit_warnings` is `true`
785     /// * `is_force_warn` was set in `DiagnosticId::Lint`
786     #[track_caller]
struct_warn_with_expectation( &self, msg: impl Into<DiagnosticMessage>, id: LintExpectationId, ) -> DiagnosticBuilder<'_, ()>787     pub fn struct_warn_with_expectation(
788         &self,
789         msg: impl Into<DiagnosticMessage>,
790         id: LintExpectationId,
791     ) -> DiagnosticBuilder<'_, ()> {
792         DiagnosticBuilder::new(self, Level::Warning(Some(id)), msg)
793     }
794 
795     /// Construct a builder at the `Allow` level with the `msg`.
796     #[rustc_lint_diagnostics]
797     #[track_caller]
struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()>798     pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
799         DiagnosticBuilder::new(self, Level::Allow, msg)
800     }
801 
802     /// Construct a builder at the `Expect` level with the `msg`.
803     #[rustc_lint_diagnostics]
804     #[track_caller]
struct_expect( &self, msg: impl Into<DiagnosticMessage>, id: LintExpectationId, ) -> DiagnosticBuilder<'_, ()>805     pub fn struct_expect(
806         &self,
807         msg: impl Into<DiagnosticMessage>,
808         id: LintExpectationId,
809     ) -> DiagnosticBuilder<'_, ()> {
810         DiagnosticBuilder::new(self, Level::Expect(id), msg)
811     }
812 
813     /// Construct a builder at the `Error` level at the given `span` and with the `msg`.
814     #[rustc_lint_diagnostics]
815     #[track_caller]
struct_span_err( &self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ErrorGuaranteed>816     pub fn struct_span_err(
817         &self,
818         span: impl Into<MultiSpan>,
819         msg: impl Into<DiagnosticMessage>,
820     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
821         let mut result = self.struct_err(msg);
822         result.set_span(span);
823         result
824     }
825 
826     /// Construct a builder at the `Error` level at the given `span`, with the `msg`, and `code`.
827     #[rustc_lint_diagnostics]
828     #[track_caller]
struct_span_err_with_code( &self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, ) -> DiagnosticBuilder<'_, ErrorGuaranteed>829     pub fn struct_span_err_with_code(
830         &self,
831         span: impl Into<MultiSpan>,
832         msg: impl Into<DiagnosticMessage>,
833         code: DiagnosticId,
834     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
835         let mut result = self.struct_span_err(span, msg);
836         result.code(code);
837         result
838     }
839 
840     /// Construct a builder at the `Error` level with the `msg`.
841     // FIXME: This method should be removed (every error should have an associated error code).
842     #[rustc_lint_diagnostics]
843     #[track_caller]
struct_err( &self, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ErrorGuaranteed>844     pub fn struct_err(
845         &self,
846         msg: impl Into<DiagnosticMessage>,
847     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
848         DiagnosticBuilder::new_guaranteeing_error(self, msg)
849     }
850 
851     /// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors.
852     #[doc(hidden)]
853     #[track_caller]
struct_err_lint(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()>854     pub fn struct_err_lint(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
855         DiagnosticBuilder::new(self, Level::Error { lint: true }, msg)
856     }
857 
858     /// Construct a builder at the `Error` level with the `msg` and the `code`.
859     #[rustc_lint_diagnostics]
860     #[track_caller]
struct_err_with_code( &self, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, ) -> DiagnosticBuilder<'_, ErrorGuaranteed>861     pub fn struct_err_with_code(
862         &self,
863         msg: impl Into<DiagnosticMessage>,
864         code: DiagnosticId,
865     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
866         let mut result = self.struct_err(msg);
867         result.code(code);
868         result
869     }
870 
871     /// Construct a builder at the `Warn` level with the `msg` and the `code`.
872     #[rustc_lint_diagnostics]
873     #[track_caller]
struct_warn_with_code( &self, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, ) -> DiagnosticBuilder<'_, ()>874     pub fn struct_warn_with_code(
875         &self,
876         msg: impl Into<DiagnosticMessage>,
877         code: DiagnosticId,
878     ) -> DiagnosticBuilder<'_, ()> {
879         let mut result = self.struct_warn(msg);
880         result.code(code);
881         result
882     }
883 
884     /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`.
885     #[rustc_lint_diagnostics]
886     #[track_caller]
struct_span_fatal( &self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, !>887     pub fn struct_span_fatal(
888         &self,
889         span: impl Into<MultiSpan>,
890         msg: impl Into<DiagnosticMessage>,
891     ) -> DiagnosticBuilder<'_, !> {
892         let mut result = self.struct_fatal(msg);
893         result.set_span(span);
894         result
895     }
896 
897     /// Construct a builder at the `Fatal` level at the given `span`, with the `msg`, and `code`.
898     #[rustc_lint_diagnostics]
899     #[track_caller]
struct_span_fatal_with_code( &self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, ) -> DiagnosticBuilder<'_, !>900     pub fn struct_span_fatal_with_code(
901         &self,
902         span: impl Into<MultiSpan>,
903         msg: impl Into<DiagnosticMessage>,
904         code: DiagnosticId,
905     ) -> DiagnosticBuilder<'_, !> {
906         let mut result = self.struct_span_fatal(span, msg);
907         result.code(code);
908         result
909     }
910 
911     /// Construct a builder at the `Error` level with the `msg`.
912     #[rustc_lint_diagnostics]
913     #[track_caller]
struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !>914     pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
915         DiagnosticBuilder::new_fatal(self, msg)
916     }
917 
918     /// Construct a builder at the `Help` level with the `msg`.
919     #[rustc_lint_diagnostics]
struct_help(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()>920     pub fn struct_help(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
921         DiagnosticBuilder::new(self, Level::Help, msg)
922     }
923 
924     /// Construct a builder at the `Note` level with the `msg`.
925     #[rustc_lint_diagnostics]
926     #[track_caller]
struct_note_without_error( &self, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ()>927     pub fn struct_note_without_error(
928         &self,
929         msg: impl Into<DiagnosticMessage>,
930     ) -> DiagnosticBuilder<'_, ()> {
931         DiagnosticBuilder::new(self, Level::Note, msg)
932     }
933 
934     #[rustc_lint_diagnostics]
935     #[track_caller]
span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> !936     pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
937         self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span);
938         FatalError.raise()
939     }
940 
941     #[rustc_lint_diagnostics]
942     #[track_caller]
span_fatal_with_code( &self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, ) -> !943     pub fn span_fatal_with_code(
944         &self,
945         span: impl Into<MultiSpan>,
946         msg: impl Into<DiagnosticMessage>,
947         code: DiagnosticId,
948     ) -> ! {
949         self.emit_diag_at_span(Diagnostic::new_with_code(Fatal, Some(code), msg), span);
950         FatalError.raise()
951     }
952 
953     #[rustc_lint_diagnostics]
954     #[track_caller]
span_err( &self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, ) -> ErrorGuaranteed955     pub fn span_err(
956         &self,
957         span: impl Into<MultiSpan>,
958         msg: impl Into<DiagnosticMessage>,
959     ) -> ErrorGuaranteed {
960         self.emit_diag_at_span(Diagnostic::new(Error { lint: false }, msg), span).unwrap()
961     }
962 
963     #[rustc_lint_diagnostics]
964     #[track_caller]
span_err_with_code( &self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, )965     pub fn span_err_with_code(
966         &self,
967         span: impl Into<MultiSpan>,
968         msg: impl Into<DiagnosticMessage>,
969         code: DiagnosticId,
970     ) {
971         self.emit_diag_at_span(
972             Diagnostic::new_with_code(Error { lint: false }, Some(code), msg),
973             span,
974         );
975     }
976 
977     #[rustc_lint_diagnostics]
978     #[track_caller]
span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>)979     pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
980         self.emit_diag_at_span(Diagnostic::new(Warning(None), msg), span);
981     }
982 
983     #[rustc_lint_diagnostics]
984     #[track_caller]
span_warn_with_code( &self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, )985     pub fn span_warn_with_code(
986         &self,
987         span: impl Into<MultiSpan>,
988         msg: impl Into<DiagnosticMessage>,
989         code: DiagnosticId,
990     ) {
991         self.emit_diag_at_span(Diagnostic::new_with_code(Warning(None), Some(code), msg), span);
992     }
993 
span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> !994     pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
995         self.inner.borrow_mut().span_bug(span, msg)
996     }
997 
998     /// For documentation on this, see `Session::delay_span_bug`.
999     #[track_caller]
delay_span_bug( &self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, ) -> ErrorGuaranteed1000     pub fn delay_span_bug(
1001         &self,
1002         span: impl Into<MultiSpan>,
1003         msg: impl Into<DiagnosticMessage>,
1004     ) -> ErrorGuaranteed {
1005         self.inner.borrow_mut().delay_span_bug(span, msg)
1006     }
1007 
1008     // FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's
1009     // where the explanation of what "good path" is (also, it should be renamed).
delay_good_path_bug(&self, msg: impl Into<DiagnosticMessage>)1010     pub fn delay_good_path_bug(&self, msg: impl Into<DiagnosticMessage>) {
1011         self.inner.borrow_mut().delay_good_path_bug(msg)
1012     }
1013 
1014     #[track_caller]
span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>)1015     pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
1016         self.emit_diag_at_span(Diagnostic::new(Bug, msg), span);
1017     }
1018 
1019     #[track_caller]
1020     #[rustc_lint_diagnostics]
span_note_without_error( &self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, )1021     pub fn span_note_without_error(
1022         &self,
1023         span: impl Into<MultiSpan>,
1024         msg: impl Into<DiagnosticMessage>,
1025     ) {
1026         self.emit_diag_at_span(Diagnostic::new(Note, msg), span);
1027     }
1028 
1029     #[track_caller]
1030     #[rustc_lint_diagnostics]
span_note_diag( &self, span: Span, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ()>1031     pub fn span_note_diag(
1032         &self,
1033         span: Span,
1034         msg: impl Into<DiagnosticMessage>,
1035     ) -> DiagnosticBuilder<'_, ()> {
1036         let mut db = DiagnosticBuilder::new(self, Note, msg);
1037         db.set_span(span);
1038         db
1039     }
1040 
1041     // NOTE: intentionally doesn't raise an error so rustc_codegen_ssa only reports fatal errors in the main thread
1042     #[rustc_lint_diagnostics]
fatal(&self, msg: impl Into<DiagnosticMessage>) -> FatalError1043     pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> FatalError {
1044         self.inner.borrow_mut().fatal(msg)
1045     }
1046 
1047     #[rustc_lint_diagnostics]
err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed1048     pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
1049         self.inner.borrow_mut().err(msg)
1050     }
1051 
1052     #[rustc_lint_diagnostics]
warn(&self, msg: impl Into<DiagnosticMessage>)1053     pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
1054         let mut db = DiagnosticBuilder::new(self, Warning(None), msg);
1055         db.emit();
1056     }
1057 
1058     #[rustc_lint_diagnostics]
note_without_error(&self, msg: impl Into<DiagnosticMessage>)1059     pub fn note_without_error(&self, msg: impl Into<DiagnosticMessage>) {
1060         DiagnosticBuilder::new(self, Note, msg).emit();
1061     }
1062 
bug(&self, msg: impl Into<DiagnosticMessage>) -> !1063     pub fn bug(&self, msg: impl Into<DiagnosticMessage>) -> ! {
1064         self.inner.borrow_mut().bug(msg)
1065     }
1066 
1067     #[inline]
err_count(&self) -> usize1068     pub fn err_count(&self) -> usize {
1069         self.inner.borrow().err_count()
1070     }
1071 
has_errors(&self) -> Option<ErrorGuaranteed>1072     pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
1073         self.inner.borrow().has_errors().then(|| {
1074             #[allow(deprecated)]
1075             ErrorGuaranteed::unchecked_claim_error_was_emitted()
1076         })
1077     }
1078 
has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed>1079     pub fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
1080         self.inner.borrow().has_errors_or_lint_errors().then(|| {
1081             #[allow(deprecated)]
1082             ErrorGuaranteed::unchecked_claim_error_was_emitted()
1083         })
1084     }
has_errors_or_delayed_span_bugs(&self) -> Option<ErrorGuaranteed>1085     pub fn has_errors_or_delayed_span_bugs(&self) -> Option<ErrorGuaranteed> {
1086         self.inner.borrow().has_errors_or_delayed_span_bugs().then(|| {
1087             #[allow(deprecated)]
1088             ErrorGuaranteed::unchecked_claim_error_was_emitted()
1089         })
1090     }
is_compilation_going_to_fail(&self) -> Option<ErrorGuaranteed>1091     pub fn is_compilation_going_to_fail(&self) -> Option<ErrorGuaranteed> {
1092         self.inner.borrow().is_compilation_going_to_fail().then(|| {
1093             #[allow(deprecated)]
1094             ErrorGuaranteed::unchecked_claim_error_was_emitted()
1095         })
1096     }
1097 
print_error_count(&self, registry: &Registry)1098     pub fn print_error_count(&self, registry: &Registry) {
1099         self.inner.borrow_mut().print_error_count(registry)
1100     }
1101 
take_future_breakage_diagnostics(&self) -> Vec<Diagnostic>1102     pub fn take_future_breakage_diagnostics(&self) -> Vec<Diagnostic> {
1103         std::mem::take(&mut self.inner.borrow_mut().future_breakage_diagnostics)
1104     }
1105 
abort_if_errors(&self)1106     pub fn abort_if_errors(&self) {
1107         self.inner.borrow_mut().abort_if_errors()
1108     }
1109 
1110     /// `true` if we haven't taught a diagnostic with this code already.
1111     /// The caller must then teach the user about such a diagnostic.
1112     ///
1113     /// Used to suppress emitting the same error multiple times with extended explanation when
1114     /// calling `-Zteach`.
must_teach(&self, code: &DiagnosticId) -> bool1115     pub fn must_teach(&self, code: &DiagnosticId) -> bool {
1116         self.inner.borrow_mut().must_teach(code)
1117     }
1118 
force_print_diagnostic(&self, db: Diagnostic)1119     pub fn force_print_diagnostic(&self, db: Diagnostic) {
1120         self.inner.borrow_mut().force_print_diagnostic(db)
1121     }
1122 
emit_diagnostic(&self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed>1123     pub fn emit_diagnostic(&self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed> {
1124         self.inner.borrow_mut().emit_diagnostic(diagnostic)
1125     }
1126 
emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed1127     pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
1128         self.create_err(err).emit()
1129     }
1130 
create_err<'a>( &'a self, err: impl IntoDiagnostic<'a>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed>1131     pub fn create_err<'a>(
1132         &'a self,
1133         err: impl IntoDiagnostic<'a>,
1134     ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
1135         err.into_diagnostic(self)
1136     }
1137 
create_warning<'a>( &'a self, warning: impl IntoDiagnostic<'a, ()>, ) -> DiagnosticBuilder<'a, ()>1138     pub fn create_warning<'a>(
1139         &'a self,
1140         warning: impl IntoDiagnostic<'a, ()>,
1141     ) -> DiagnosticBuilder<'a, ()> {
1142         warning.into_diagnostic(self)
1143     }
1144 
emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>)1145     pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
1146         self.create_warning(warning).emit()
1147     }
1148 
create_almost_fatal<'a>( &'a self, fatal: impl IntoDiagnostic<'a, FatalError>, ) -> DiagnosticBuilder<'a, FatalError>1149     pub fn create_almost_fatal<'a>(
1150         &'a self,
1151         fatal: impl IntoDiagnostic<'a, FatalError>,
1152     ) -> DiagnosticBuilder<'a, FatalError> {
1153         fatal.into_diagnostic(self)
1154     }
1155 
emit_almost_fatal<'a>( &'a self, fatal: impl IntoDiagnostic<'a, FatalError>, ) -> FatalError1156     pub fn emit_almost_fatal<'a>(
1157         &'a self,
1158         fatal: impl IntoDiagnostic<'a, FatalError>,
1159     ) -> FatalError {
1160         self.create_almost_fatal(fatal).emit()
1161     }
1162 
create_fatal<'a>( &'a self, fatal: impl IntoDiagnostic<'a, !>, ) -> DiagnosticBuilder<'a, !>1163     pub fn create_fatal<'a>(
1164         &'a self,
1165         fatal: impl IntoDiagnostic<'a, !>,
1166     ) -> DiagnosticBuilder<'a, !> {
1167         fatal.into_diagnostic(self)
1168     }
1169 
emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> !1170     pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! {
1171         self.create_fatal(fatal).emit()
1172     }
1173 
create_bug<'a>( &'a self, bug: impl IntoDiagnostic<'a, diagnostic_builder::Bug>, ) -> DiagnosticBuilder<'a, diagnostic_builder::Bug>1174     pub fn create_bug<'a>(
1175         &'a self,
1176         bug: impl IntoDiagnostic<'a, diagnostic_builder::Bug>,
1177     ) -> DiagnosticBuilder<'a, diagnostic_builder::Bug> {
1178         bug.into_diagnostic(self)
1179     }
1180 
emit_bug<'a>( &'a self, bug: impl IntoDiagnostic<'a, diagnostic_builder::Bug>, ) -> diagnostic_builder::Bug1181     pub fn emit_bug<'a>(
1182         &'a self,
1183         bug: impl IntoDiagnostic<'a, diagnostic_builder::Bug>,
1184     ) -> diagnostic_builder::Bug {
1185         self.create_bug(bug).emit()
1186     }
1187 
emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted1188     pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted {
1189         self.create_note(note).emit()
1190     }
1191 
create_note<'a>( &'a self, note: impl IntoDiagnostic<'a, Noted>, ) -> DiagnosticBuilder<'a, Noted>1192     pub fn create_note<'a>(
1193         &'a self,
1194         note: impl IntoDiagnostic<'a, Noted>,
1195     ) -> DiagnosticBuilder<'a, Noted> {
1196         note.into_diagnostic(self)
1197     }
1198 
emit_diag_at_span( &self, mut diag: Diagnostic, sp: impl Into<MultiSpan>, ) -> Option<ErrorGuaranteed>1199     fn emit_diag_at_span(
1200         &self,
1201         mut diag: Diagnostic,
1202         sp: impl Into<MultiSpan>,
1203     ) -> Option<ErrorGuaranteed> {
1204         let mut inner = self.inner.borrow_mut();
1205         inner.emit_diagnostic(diag.set_span(sp))
1206     }
1207 
emit_artifact_notification(&self, path: &Path, artifact_type: &str)1208     pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
1209         self.inner.borrow_mut().emit_artifact_notification(path, artifact_type)
1210     }
1211 
emit_future_breakage_report(&self, diags: Vec<Diagnostic>)1212     pub fn emit_future_breakage_report(&self, diags: Vec<Diagnostic>) {
1213         self.inner.borrow_mut().emitter.emit_future_breakage_report(diags)
1214     }
1215 
emit_unused_externs( &self, lint_level: rustc_lint_defs::Level, loud: bool, unused_externs: &[&str], )1216     pub fn emit_unused_externs(
1217         &self,
1218         lint_level: rustc_lint_defs::Level,
1219         loud: bool,
1220         unused_externs: &[&str],
1221     ) {
1222         let mut inner = self.inner.borrow_mut();
1223 
1224         if loud && lint_level.is_error() {
1225             inner.bump_err_count();
1226         }
1227 
1228         inner.emit_unused_externs(lint_level, unused_externs)
1229     }
1230 
update_unstable_expectation_id( &self, unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>, )1231     pub fn update_unstable_expectation_id(
1232         &self,
1233         unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>,
1234     ) {
1235         let mut inner = self.inner.borrow_mut();
1236         let diags = std::mem::take(&mut inner.unstable_expect_diagnostics);
1237         inner.check_unstable_expect_diagnostics = true;
1238 
1239         if !diags.is_empty() {
1240             inner.suppressed_expected_diag = true;
1241             for mut diag in diags.into_iter() {
1242                 diag.update_unstable_expectation_id(unstable_to_stable);
1243 
1244                 // Here the diagnostic is given back to `emit_diagnostic` where it was first
1245                 // intercepted. Now it should be processed as usual, since the unstable expectation
1246                 // id is now stable.
1247                 inner.emit_diagnostic(&mut diag);
1248             }
1249         }
1250 
1251         inner
1252             .stashed_diagnostics
1253             .values_mut()
1254             .for_each(|diag| diag.update_unstable_expectation_id(unstable_to_stable));
1255         inner
1256             .future_breakage_diagnostics
1257             .iter_mut()
1258             .for_each(|diag| diag.update_unstable_expectation_id(unstable_to_stable));
1259     }
1260 
1261     /// This methods steals all [`LintExpectationId`]s that are stored inside
1262     /// [`HandlerInner`] and indicate that the linked expectation has been fulfilled.
1263     #[must_use]
steal_fulfilled_expectation_ids(&self) -> FxHashSet<LintExpectationId>1264     pub fn steal_fulfilled_expectation_ids(&self) -> FxHashSet<LintExpectationId> {
1265         assert!(
1266             self.inner.borrow().unstable_expect_diagnostics.is_empty(),
1267             "`HandlerInner::unstable_expect_diagnostics` should be empty at this point",
1268         );
1269         std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
1270     }
1271 
flush_delayed(&self)1272     pub fn flush_delayed(&self) {
1273         let mut inner = self.inner.lock();
1274         let bugs = std::mem::replace(&mut inner.delayed_span_bugs, Vec::new());
1275         inner.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued");
1276     }
1277 }
1278 
1279 impl HandlerInner {
must_teach(&mut self, code: &DiagnosticId) -> bool1280     fn must_teach(&mut self, code: &DiagnosticId) -> bool {
1281         self.taught_diagnostics.insert(code.clone())
1282     }
1283 
force_print_diagnostic(&mut self, db: Diagnostic)1284     fn force_print_diagnostic(&mut self, db: Diagnostic) {
1285         self.emitter.emit_diagnostic(&db);
1286     }
1287 
1288     /// Emit all stashed diagnostics.
emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed>1289     fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
1290         let has_errors = self.has_errors();
1291         let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::<Vec<_>>();
1292         let mut reported = None;
1293         for mut diag in diags {
1294             // Decrement the count tracking the stash; emitting will increment it.
1295             if diag.is_error() {
1296                 if matches!(diag.level, Level::Error { lint: true }) {
1297                     self.lint_err_count -= 1;
1298                 } else {
1299                     self.err_count -= 1;
1300                 }
1301             } else {
1302                 if diag.is_force_warn() {
1303                     self.warn_count -= 1;
1304                 } else {
1305                     // Unless they're forced, don't flush stashed warnings when
1306                     // there are errors, to avoid causing warning overload. The
1307                     // stash would've been stolen already if it were important.
1308                     if has_errors {
1309                         continue;
1310                     }
1311                 }
1312             }
1313             let reported_this = self.emit_diagnostic(&mut diag);
1314             reported = reported.or(reported_this);
1315         }
1316         reported
1317     }
1318 
1319     // FIXME(eddyb) this should ideally take `diagnostic` by value.
emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed>1320     fn emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed> {
1321         // The `LintExpectationId` can be stable or unstable depending on when it was created.
1322         // Diagnostics created before the definition of `HirId`s are unstable and can not yet
1323         // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
1324         // a stable one by the `LintLevelsBuilder`.
1325         if let Some(LintExpectationId::Unstable { .. }) = diagnostic.level.get_expectation_id() {
1326             self.unstable_expect_diagnostics.push(diagnostic.clone());
1327             return None;
1328         }
1329 
1330         if diagnostic.level == Level::DelayedBug {
1331             // FIXME(eddyb) this should check for `has_errors` and stop pushing
1332             // once *any* errors were emitted (and truncate `delayed_span_bugs`
1333             // when an error is first emitted, also), but maybe there's a case
1334             // in which that's not sound? otherwise this is really inefficient.
1335             let backtrace = std::backtrace::Backtrace::capture();
1336             self.delayed_span_bugs
1337                 .push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace));
1338 
1339             if !self.flags.report_delayed_bugs {
1340                 #[allow(deprecated)]
1341                 return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
1342             }
1343         }
1344 
1345         if diagnostic.has_future_breakage() {
1346             // Future breakages aren't emitted if they're Level::Allowed,
1347             // but they still need to be constructed and stashed below,
1348             // so they'll trigger the good-path bug check.
1349             self.suppressed_expected_diag = true;
1350             self.future_breakage_diagnostics.push(diagnostic.clone());
1351         }
1352 
1353         if let Some(expectation_id) = diagnostic.level.get_expectation_id() {
1354             self.suppressed_expected_diag = true;
1355             self.fulfilled_expectations.insert(expectation_id.normalize());
1356         }
1357 
1358         if matches!(diagnostic.level, Warning(_))
1359             && !self.flags.can_emit_warnings
1360             && !diagnostic.is_force_warn()
1361         {
1362             if diagnostic.has_future_breakage() {
1363                 (*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
1364             }
1365             return None;
1366         }
1367 
1368         if matches!(diagnostic.level, Level::Expect(_) | Level::Allow) {
1369             (*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
1370             return None;
1371         }
1372 
1373         let mut guaranteed = None;
1374         (*TRACK_DIAGNOSTICS)(diagnostic, &mut |diagnostic| {
1375             if let Some(ref code) = diagnostic.code {
1376                 self.emitted_diagnostic_codes.insert(code.clone());
1377             }
1378 
1379             let already_emitted = |this: &mut Self| {
1380                 let mut hasher = StableHasher::new();
1381                 diagnostic.hash(&mut hasher);
1382                 let diagnostic_hash = hasher.finish();
1383                 !this.emitted_diagnostics.insert(diagnostic_hash)
1384             };
1385 
1386             // Only emit the diagnostic if we've been asked to deduplicate or
1387             // haven't already emitted an equivalent diagnostic.
1388             if !(self.flags.deduplicate_diagnostics && already_emitted(self)) {
1389                 debug!(?diagnostic);
1390                 debug!(?self.emitted_diagnostics);
1391                 let already_emitted_sub = |sub: &mut SubDiagnostic| {
1392                     debug!(?sub);
1393                     if sub.level != Level::OnceNote {
1394                         return false;
1395                     }
1396                     let mut hasher = StableHasher::new();
1397                     sub.hash(&mut hasher);
1398                     let diagnostic_hash = hasher.finish();
1399                     debug!(?diagnostic_hash);
1400                     !self.emitted_diagnostics.insert(diagnostic_hash)
1401                 };
1402 
1403                 diagnostic.children.extract_if(already_emitted_sub).for_each(|_| {});
1404 
1405                 self.emitter.emit_diagnostic(diagnostic);
1406                 if diagnostic.is_error() {
1407                     self.deduplicated_err_count += 1;
1408                 } else if let Warning(_) = diagnostic.level {
1409                     self.deduplicated_warn_count += 1;
1410                 }
1411             }
1412             if diagnostic.is_error() {
1413                 if matches!(diagnostic.level, Level::Error { lint: true }) {
1414                     self.bump_lint_err_count();
1415                 } else {
1416                     self.bump_err_count();
1417                 }
1418 
1419                 #[allow(deprecated)]
1420                 {
1421                     guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
1422                 }
1423             } else {
1424                 self.bump_warn_count();
1425             }
1426         });
1427 
1428         guaranteed
1429     }
1430 
emit_artifact_notification(&mut self, path: &Path, artifact_type: &str)1431     fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {
1432         self.emitter.emit_artifact_notification(path, artifact_type);
1433     }
1434 
emit_unused_externs(&mut self, lint_level: rustc_lint_defs::Level, unused_externs: &[&str])1435     fn emit_unused_externs(&mut self, lint_level: rustc_lint_defs::Level, unused_externs: &[&str]) {
1436         self.emitter.emit_unused_externs(lint_level, unused_externs);
1437     }
1438 
treat_err_as_bug(&self) -> bool1439     fn treat_err_as_bug(&self) -> bool {
1440         self.flags.treat_err_as_bug.is_some_and(|c| {
1441             self.err_count() + self.lint_err_count + self.delayed_bug_count() >= c.get()
1442         })
1443     }
1444 
delayed_bug_count(&self) -> usize1445     fn delayed_bug_count(&self) -> usize {
1446         self.delayed_span_bugs.len() + self.delayed_good_path_bugs.len()
1447     }
1448 
print_error_count(&mut self, registry: &Registry)1449     fn print_error_count(&mut self, registry: &Registry) {
1450         self.emit_stashed_diagnostics();
1451 
1452         let warnings = match self.deduplicated_warn_count {
1453             0 => Cow::from(""),
1454             1 => Cow::from("1 warning emitted"),
1455             count => Cow::from(format!("{count} warnings emitted")),
1456         };
1457         let errors = match self.deduplicated_err_count {
1458             0 => Cow::from(""),
1459             1 => Cow::from("aborting due to previous error"),
1460             count => Cow::from(format!("aborting due to {count} previous errors")),
1461         };
1462         if self.treat_err_as_bug() {
1463             return;
1464         }
1465 
1466         match (errors.len(), warnings.len()) {
1467             (0, 0) => return,
1468             (0, _) => self.emitter.emit_diagnostic(&Diagnostic::new(
1469                 Level::Warning(None),
1470                 DiagnosticMessage::Str(warnings),
1471             )),
1472             (_, 0) => {
1473                 let _ = self.fatal(errors);
1474             }
1475             (_, _) => {
1476                 let _ = self.fatal(format!("{}; {}", &errors, &warnings));
1477             }
1478         }
1479 
1480         let can_show_explain = self.emitter.should_show_explain();
1481         let are_there_diagnostics = !self.emitted_diagnostic_codes.is_empty();
1482         if can_show_explain && are_there_diagnostics {
1483             let mut error_codes = self
1484                 .emitted_diagnostic_codes
1485                 .iter()
1486                 .filter_map(|x| match &x {
1487                     DiagnosticId::Error(s) if registry.try_find_description(s).is_ok() => {
1488                         Some(s.clone())
1489                     }
1490                     _ => None,
1491                 })
1492                 .collect::<Vec<_>>();
1493             if !error_codes.is_empty() {
1494                 error_codes.sort();
1495                 if error_codes.len() > 1 {
1496                     let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
1497                     self.failure(format!(
1498                         "Some errors have detailed explanations: {}{}",
1499                         error_codes[..limit].join(", "),
1500                         if error_codes.len() > 9 { "..." } else { "." }
1501                     ));
1502                     self.failure(format!(
1503                         "For more information about an error, try \
1504                          `rustc --explain {}`.",
1505                         &error_codes[0]
1506                     ));
1507                 } else {
1508                     self.failure(format!(
1509                         "For more information about this error, try \
1510                          `rustc --explain {}`.",
1511                         &error_codes[0]
1512                     ));
1513                 }
1514             }
1515         }
1516     }
1517 
stash(&mut self, key: (Span, StashKey), diagnostic: Diagnostic)1518     fn stash(&mut self, key: (Span, StashKey), diagnostic: Diagnostic) {
1519         // Track the diagnostic for counts, but don't panic-if-treat-err-as-bug
1520         // yet; that happens when we actually emit the diagnostic.
1521         if diagnostic.is_error() {
1522             if matches!(diagnostic.level, Level::Error { lint: true }) {
1523                 self.lint_err_count += 1;
1524             } else {
1525                 self.err_count += 1;
1526             }
1527         } else {
1528             // Warnings are only automatically flushed if they're forced.
1529             if diagnostic.is_force_warn() {
1530                 self.warn_count += 1;
1531             }
1532         }
1533 
1534         // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
1535         // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key.
1536         // See the PR for a discussion.
1537         self.stashed_diagnostics.insert(key, diagnostic);
1538     }
1539 
steal(&mut self, key: (Span, StashKey)) -> Option<Diagnostic>1540     fn steal(&mut self, key: (Span, StashKey)) -> Option<Diagnostic> {
1541         let diagnostic = self.stashed_diagnostics.remove(&key)?;
1542         if diagnostic.is_error() {
1543             if matches!(diagnostic.level, Level::Error { lint: true }) {
1544                 self.lint_err_count -= 1;
1545             } else {
1546                 self.err_count -= 1;
1547             }
1548         } else {
1549             if diagnostic.is_force_warn() {
1550                 self.warn_count -= 1;
1551             }
1552         }
1553         Some(diagnostic)
1554     }
1555 
1556     #[inline]
err_count(&self) -> usize1557     fn err_count(&self) -> usize {
1558         self.err_count
1559     }
1560 
has_errors(&self) -> bool1561     fn has_errors(&self) -> bool {
1562         self.err_count() > 0
1563     }
has_errors_or_lint_errors(&self) -> bool1564     fn has_errors_or_lint_errors(&self) -> bool {
1565         self.has_errors() || self.lint_err_count > 0
1566     }
has_errors_or_delayed_span_bugs(&self) -> bool1567     fn has_errors_or_delayed_span_bugs(&self) -> bool {
1568         self.has_errors() || !self.delayed_span_bugs.is_empty()
1569     }
has_any_message(&self) -> bool1570     fn has_any_message(&self) -> bool {
1571         self.err_count() > 0 || self.lint_err_count > 0 || self.warn_count > 0
1572     }
1573 
is_compilation_going_to_fail(&self) -> bool1574     fn is_compilation_going_to_fail(&self) -> bool {
1575         self.has_errors() || self.lint_err_count > 0 || !self.delayed_span_bugs.is_empty()
1576     }
1577 
abort_if_errors(&mut self)1578     fn abort_if_errors(&mut self) {
1579         self.emit_stashed_diagnostics();
1580 
1581         if self.has_errors() {
1582             FatalError.raise();
1583         }
1584     }
1585 
1586     #[track_caller]
span_bug(&mut self, sp: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> !1587     fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
1588         self.emit_diag_at_span(Diagnostic::new(Bug, msg), sp);
1589         panic::panic_any(ExplicitBug);
1590     }
1591 
emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into<MultiSpan>)1592     fn emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into<MultiSpan>) {
1593         self.emit_diagnostic(diag.set_span(sp));
1594     }
1595 
1596     /// For documentation on this, see `Session::delay_span_bug`.
1597     #[track_caller]
delay_span_bug( &mut self, sp: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, ) -> ErrorGuaranteed1598     fn delay_span_bug(
1599         &mut self,
1600         sp: impl Into<MultiSpan>,
1601         msg: impl Into<DiagnosticMessage>,
1602     ) -> ErrorGuaranteed {
1603         // This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
1604         // incrementing `err_count` by one, so we need to +1 the comparing.
1605         // FIXME: Would be nice to increment err_count in a more coherent way.
1606         if self.flags.treat_err_as_bug.is_some_and(|c| {
1607             self.err_count() + self.lint_err_count + self.delayed_bug_count() + 1 >= c.get()
1608         }) {
1609             // FIXME: don't abort here if report_delayed_bugs is off
1610             self.span_bug(sp, msg);
1611         }
1612         let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg);
1613         diagnostic.set_span(sp.into());
1614         self.emit_diagnostic(&mut diagnostic).unwrap()
1615     }
1616 
1617     // FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's
1618     // where the explanation of what "good path" is (also, it should be renamed).
delay_good_path_bug(&mut self, msg: impl Into<DiagnosticMessage>)1619     fn delay_good_path_bug(&mut self, msg: impl Into<DiagnosticMessage>) {
1620         let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg);
1621         if self.flags.report_delayed_bugs {
1622             self.emit_diagnostic(&mut diagnostic);
1623         }
1624         let backtrace = std::backtrace::Backtrace::capture();
1625         self.delayed_good_path_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
1626     }
1627 
failure(&mut self, msg: impl Into<DiagnosticMessage>)1628     fn failure(&mut self, msg: impl Into<DiagnosticMessage>) {
1629         self.emit_diagnostic(&mut Diagnostic::new(FailureNote, msg));
1630     }
1631 
fatal(&mut self, msg: impl Into<DiagnosticMessage>) -> FatalError1632     fn fatal(&mut self, msg: impl Into<DiagnosticMessage>) -> FatalError {
1633         self.emit(Fatal, msg);
1634         FatalError
1635     }
1636 
err(&mut self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed1637     fn err(&mut self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
1638         self.emit(Error { lint: false }, msg)
1639     }
1640 
1641     /// Emit an error; level should be `Error` or `Fatal`.
emit(&mut self, level: Level, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed1642     fn emit(&mut self, level: Level, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
1643         if self.treat_err_as_bug() {
1644             self.bug(msg);
1645         }
1646         self.emit_diagnostic(&mut Diagnostic::new(level, msg)).unwrap()
1647     }
1648 
bug(&mut self, msg: impl Into<DiagnosticMessage>) -> !1649     fn bug(&mut self, msg: impl Into<DiagnosticMessage>) -> ! {
1650         self.emit_diagnostic(&mut Diagnostic::new(Bug, msg));
1651         panic::panic_any(ExplicitBug);
1652     }
1653 
flush_delayed( &mut self, bugs: impl IntoIterator<Item = DelayedDiagnostic>, explanation: impl Into<DiagnosticMessage> + Copy, )1654     fn flush_delayed(
1655         &mut self,
1656         bugs: impl IntoIterator<Item = DelayedDiagnostic>,
1657         explanation: impl Into<DiagnosticMessage> + Copy,
1658     ) {
1659         let mut no_bugs = true;
1660         for bug in bugs {
1661             let mut bug = bug.decorate();
1662 
1663             if no_bugs {
1664                 // Put the overall explanation before the `DelayedBug`s, to
1665                 // frame them better (e.g. separate warnings from them).
1666                 self.emit_diagnostic(&mut Diagnostic::new(Bug, explanation));
1667                 no_bugs = false;
1668             }
1669 
1670             // "Undelay" the `DelayedBug`s (into plain `Bug`s).
1671             if bug.level != Level::DelayedBug {
1672                 // NOTE(eddyb) not panicking here because we're already producing
1673                 // an ICE, and the more information the merrier.
1674                 bug.note(format!(
1675                     "`flushed_delayed` got diagnostic with level {:?}, \
1676                      instead of the expected `DelayedBug`",
1677                     bug.level,
1678                 ));
1679             }
1680             bug.level = Level::Bug;
1681 
1682             self.emit_diagnostic(&mut bug);
1683         }
1684 
1685         // Panic with `DelayedBugPanic` to avoid "unexpected panic" messages.
1686         if !no_bugs {
1687             panic::panic_any(DelayedBugPanic);
1688         }
1689     }
1690 
bump_lint_err_count(&mut self)1691     fn bump_lint_err_count(&mut self) {
1692         self.lint_err_count += 1;
1693         self.panic_if_treat_err_as_bug();
1694     }
1695 
bump_err_count(&mut self)1696     fn bump_err_count(&mut self) {
1697         self.err_count += 1;
1698         self.panic_if_treat_err_as_bug();
1699     }
1700 
bump_warn_count(&mut self)1701     fn bump_warn_count(&mut self) {
1702         self.warn_count += 1;
1703     }
1704 
panic_if_treat_err_as_bug(&self)1705     fn panic_if_treat_err_as_bug(&self) {
1706         if self.treat_err_as_bug() {
1707             match (
1708                 self.err_count() + self.lint_err_count,
1709                 self.delayed_bug_count(),
1710                 self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0),
1711             ) {
1712                 (1, 0, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
1713                 (0, 1, 1) => panic!("aborting due delayed bug with `-Z treat-err-as-bug=1`"),
1714                 (count, delayed_count, as_bug) => {
1715                     if delayed_count > 0 {
1716                         panic!(
1717                             "aborting after {} errors and {} delayed bugs due to `-Z treat-err-as-bug={}`",
1718                             count, delayed_count, as_bug,
1719                         )
1720                     } else {
1721                         panic!(
1722                             "aborting after {} errors due to `-Z treat-err-as-bug={}`",
1723                             count, as_bug,
1724                         )
1725                     }
1726                 }
1727             }
1728         }
1729     }
1730 }
1731 
1732 struct DelayedDiagnostic {
1733     inner: Diagnostic,
1734     note: Backtrace,
1735 }
1736 
1737 impl DelayedDiagnostic {
with_backtrace(diagnostic: Diagnostic, backtrace: Backtrace) -> Self1738     fn with_backtrace(diagnostic: Diagnostic, backtrace: Backtrace) -> Self {
1739         DelayedDiagnostic { inner: diagnostic, note: backtrace }
1740     }
1741 
decorate(mut self) -> Diagnostic1742     fn decorate(mut self) -> Diagnostic {
1743         match self.note.status() {
1744             BacktraceStatus::Captured => {
1745                 self.inner.note(format!("delayed at {}\n{}", self.inner.emitted_at, self.note));
1746             }
1747             // Avoid the needless newline when no backtrace has been captured,
1748             // the display impl should just be a single line.
1749             _ => {
1750                 self.inner.note(format!("delayed at {} - {}", self.inner.emitted_at, self.note));
1751             }
1752         }
1753 
1754         self.inner
1755     }
1756 }
1757 
1758 #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)]
1759 pub enum Level {
1760     Bug,
1761     DelayedBug,
1762     Fatal,
1763     Error {
1764         /// If this error comes from a lint, don't abort compilation even when abort_if_errors() is called.
1765         lint: bool,
1766     },
1767     /// This [`LintExpectationId`] is used for expected lint diagnostics, which should
1768     /// also emit a warning due to the `force-warn` flag. In all other cases this should
1769     /// be `None`.
1770     Warning(Option<LintExpectationId>),
1771     Note,
1772     /// A note that is only emitted once.
1773     OnceNote,
1774     Help,
1775     FailureNote,
1776     Allow,
1777     Expect(LintExpectationId),
1778 }
1779 
1780 impl fmt::Display for Level {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1781     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1782         self.to_str().fmt(f)
1783     }
1784 }
1785 
1786 impl Level {
color(self) -> ColorSpec1787     fn color(self) -> ColorSpec {
1788         let mut spec = ColorSpec::new();
1789         match self {
1790             Bug | DelayedBug | Fatal | Error { .. } => {
1791                 spec.set_fg(Some(Color::Red)).set_intense(true);
1792             }
1793             Warning(_) => {
1794                 spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
1795             }
1796             Note | OnceNote => {
1797                 spec.set_fg(Some(Color::Green)).set_intense(true);
1798             }
1799             Help => {
1800                 spec.set_fg(Some(Color::Cyan)).set_intense(true);
1801             }
1802             FailureNote => {}
1803             Allow | Expect(_) => unreachable!(),
1804         }
1805         spec
1806     }
1807 
to_str(self) -> &'static str1808     pub fn to_str(self) -> &'static str {
1809         match self {
1810             Bug | DelayedBug => "error: internal compiler error",
1811             Fatal | Error { .. } => "error",
1812             Warning(_) => "warning",
1813             Note | OnceNote => "note",
1814             Help => "help",
1815             FailureNote => "failure-note",
1816             Allow => panic!("Shouldn't call on allowed error"),
1817             Expect(_) => panic!("Shouldn't call on expected error"),
1818         }
1819     }
1820 
is_failure_note(&self) -> bool1821     pub fn is_failure_note(&self) -> bool {
1822         matches!(*self, FailureNote)
1823     }
1824 
get_expectation_id(&self) -> Option<LintExpectationId>1825     pub fn get_expectation_id(&self) -> Option<LintExpectationId> {
1826         match self {
1827             Level::Expect(id) | Level::Warning(Some(id)) => Some(*id),
1828             _ => None,
1829         }
1830     }
1831 }
1832 
1833 // FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite.
add_elided_lifetime_in_path_suggestion( source_map: &SourceMap, diag: &mut Diagnostic, n: usize, path_span: Span, incl_angl_brckt: bool, insertion_span: Span, )1834 pub fn add_elided_lifetime_in_path_suggestion(
1835     source_map: &SourceMap,
1836     diag: &mut Diagnostic,
1837     n: usize,
1838     path_span: Span,
1839     incl_angl_brckt: bool,
1840     insertion_span: Span,
1841 ) {
1842     diag.span_label(path_span, format!("expected lifetime parameter{}", pluralize!(n)));
1843     if !source_map.is_span_accessible(insertion_span) {
1844         // Do not try to suggest anything if generated by a proc-macro.
1845         return;
1846     }
1847     let anon_lts = vec!["'_"; n].join(", ");
1848     let suggestion =
1849         if incl_angl_brckt { format!("<{}>", anon_lts) } else { format!("{}, ", anon_lts) };
1850     diag.span_suggestion_verbose(
1851         insertion_span.shrink_to_hi(),
1852         format!("indicate the anonymous lifetime{}", pluralize!(n)),
1853         suggestion,
1854         Applicability::MachineApplicable,
1855     );
1856 }
1857 
1858 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
1859 pub enum TerminalUrl {
1860     No,
1861     Yes,
1862     Auto,
1863 }
1864