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