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