]> git.proxmox.com Git - rustc.git/blob - vendor/rustc-ap-rustc_errors/src/lib.rs
New upstream version 1.52.1+dfsg1
[rustc.git] / vendor / rustc-ap-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(crate_visibility_modifier)]
7 #![feature(backtrace)]
8 #![feature(nll)]
9
10 #[macro_use]
11 extern crate rustc_macros;
12
13 pub use emitter::ColorConfig;
14
15 use tracing::debug;
16 use Level::*;
17
18 use emitter::{is_case_difference, Emitter, EmitterWriter};
19 use registry::Registry;
20 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
21 use rustc_data_structures::stable_hasher::StableHasher;
22 use rustc_data_structures::sync::{self, Lock, Lrc};
23 use rustc_data_structures::AtomicRef;
24 use rustc_lint_defs::FutureBreakage;
25 pub use rustc_lint_defs::{pluralize, Applicability};
26 use rustc_span::source_map::SourceMap;
27 use rustc_span::{Loc, MultiSpan, Span};
28
29 use std::borrow::Cow;
30 use std::panic;
31 use std::path::Path;
32 use std::{error, fmt};
33
34 use termcolor::{Color, ColorSpec};
35
36 pub mod annotate_snippet_emitter_writer;
37 mod diagnostic;
38 mod diagnostic_builder;
39 pub mod emitter;
40 pub mod json;
41 mod lock;
42 pub mod registry;
43 mod snippet;
44 mod styled_buffer;
45 pub use snippet::Style;
46
47 pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
48
49 // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
50 // (See also the comment on `DiagnosticBuilderInner`.)
51 #[cfg(target_arch = "x86_64")]
52 rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
53
54 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
55 pub enum SuggestionStyle {
56 /// Hide the suggested code when displaying this suggestion inline.
57 HideCodeInline,
58 /// Always hide the suggested code but display the message.
59 HideCodeAlways,
60 /// Do not display this suggestion in the cli output, it is only meant for tools.
61 CompletelyHidden,
62 /// Always show the suggested code.
63 /// This will *not* show the code if the suggestion is inline *and* the suggested code is
64 /// empty.
65 ShowCode,
66 /// Always show the suggested code independently.
67 ShowAlways,
68 }
69
70 impl SuggestionStyle {
71 fn hide_inline(&self) -> bool {
72 !matches!(*self, SuggestionStyle::ShowCode)
73 }
74 }
75
76 #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
77 pub struct CodeSuggestion {
78 /// Each substitute can have multiple variants due to multiple
79 /// applicable suggestions
80 ///
81 /// `foo.bar` might be replaced with `a.b` or `x.y` by replacing
82 /// `foo` and `bar` on their own:
83 ///
84 /// ```
85 /// vec![
86 /// Substitution { parts: vec![(0..3, "a"), (4..7, "b")] },
87 /// Substitution { parts: vec![(0..3, "x"), (4..7, "y")] },
88 /// ]
89 /// ```
90 ///
91 /// or by replacing the entire span:
92 ///
93 /// ```
94 /// vec![
95 /// Substitution { parts: vec![(0..7, "a.b")] },
96 /// Substitution { parts: vec![(0..7, "x.y")] },
97 /// ]
98 /// ```
99 pub substitutions: Vec<Substitution>,
100 pub msg: String,
101 /// Visual representation of this suggestion.
102 pub style: SuggestionStyle,
103 /// Whether or not the suggestion is approximate
104 ///
105 /// Sometimes we may show suggestions with placeholders,
106 /// which are useful for users but not useful for
107 /// tools like rustfix
108 pub applicability: Applicability,
109 }
110
111 #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
112 /// See the docs on `CodeSuggestion::substitutions`
113 pub struct Substitution {
114 pub parts: Vec<SubstitutionPart>,
115 }
116
117 #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
118 pub struct SubstitutionPart {
119 pub span: Span,
120 pub snippet: String,
121 }
122
123 impl CodeSuggestion {
124 /// Returns the assembled code suggestions, whether they should be shown with an underline
125 /// and whether the substitution only differs in capitalization.
126 pub fn splice_lines(&self, sm: &SourceMap) -> Vec<(String, Vec<SubstitutionPart>, bool)> {
127 use rustc_span::{CharPos, Pos};
128
129 fn push_trailing(
130 buf: &mut String,
131 line_opt: Option<&Cow<'_, str>>,
132 lo: &Loc,
133 hi_opt: Option<&Loc>,
134 ) {
135 let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
136 if let Some(line) = line_opt {
137 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
138 let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
139 match hi_opt {
140 Some(hi) if hi > lo => buf.push_str(&line[lo..hi]),
141 Some(_) => (),
142 None => buf.push_str(&line[lo..]),
143 }
144 }
145 if hi_opt.is_none() {
146 buf.push('\n');
147 }
148 }
149 }
150
151 assert!(!self.substitutions.is_empty());
152
153 self.substitutions
154 .iter()
155 .filter(|subst| {
156 // Suggestions coming from macros can have malformed spans. This is a heavy
157 // handed approach to avoid ICEs by ignoring the suggestion outright.
158 let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
159 if invalid {
160 debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
161 }
162 !invalid
163 })
164 .cloned()
165 .filter_map(|mut substitution| {
166 // Assumption: all spans are in the same file, and all spans
167 // are disjoint. Sort in ascending order.
168 substitution.parts.sort_by_key(|part| part.span.lo());
169
170 // Find the bounding span.
171 let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
172 let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
173 let bounding_span = Span::with_root_ctxt(lo, hi);
174 // The different spans might belong to different contexts, if so ignore suggestion.
175 let lines = sm.span_to_lines(bounding_span).ok()?;
176 assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
177
178 // We can't splice anything if the source is unavailable.
179 if !sm.ensure_source_file_source_present(lines.file.clone()) {
180 return None;
181 }
182
183 // To build up the result, we do this for each span:
184 // - push the line segment trailing the previous span
185 // (at the beginning a "phantom" span pointing at the start of the line)
186 // - push lines between the previous and current span (if any)
187 // - if the previous and current span are not on the same line
188 // push the line segment leading up to the current span
189 // - splice in the span substitution
190 //
191 // Finally push the trailing line segment of the last span
192 let sf = &lines.file;
193 let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
194 prev_hi.col = CharPos::from_usize(0);
195 let mut prev_line =
196 lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
197 let mut buf = String::new();
198
199 for part in &substitution.parts {
200 let cur_lo = sm.lookup_char_pos(part.span.lo());
201 if prev_hi.line == cur_lo.line {
202 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
203 } else {
204 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
205 // push lines between the previous and current span (if any)
206 for idx in prev_hi.line..(cur_lo.line - 1) {
207 if let Some(line) = sf.get_line(idx) {
208 buf.push_str(line.as_ref());
209 buf.push('\n');
210 }
211 }
212 if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
213 let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
214 Some((i, _)) => i,
215 None => cur_line.len(),
216 };
217 buf.push_str(&cur_line[..end]);
218 }
219 }
220 buf.push_str(&part.snippet);
221 prev_hi = sm.lookup_char_pos(part.span.hi());
222 prev_line = sf.get_line(prev_hi.line - 1);
223 }
224 let only_capitalization = is_case_difference(sm, &buf, bounding_span);
225 // if the replacement already ends with a newline, don't print the next line
226 if !buf.ends_with('\n') {
227 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
228 }
229 // remove trailing newlines
230 while buf.ends_with('\n') {
231 buf.pop();
232 }
233 Some((buf, substitution.parts, only_capitalization))
234 })
235 .collect()
236 }
237 }
238
239 pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
240
241 /// Signifies that the compiler died with an explicit call to `.bug`
242 /// or `.span_bug` rather than a failed assertion, etc.
243 #[derive(Copy, Clone, Debug)]
244 pub struct ExplicitBug;
245
246 impl fmt::Display for ExplicitBug {
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 write!(f, "parser internal bug")
249 }
250 }
251
252 impl error::Error for ExplicitBug {}
253
254 pub use diagnostic::{Diagnostic, DiagnosticId, DiagnosticStyledString, SubDiagnostic};
255 pub use diagnostic_builder::DiagnosticBuilder;
256
257 /// A handler deals with errors and other compiler output.
258 /// Certain errors (fatal, bug, unimpl) may cause immediate exit,
259 /// others log errors for later reporting.
260 pub struct Handler {
261 flags: HandlerFlags,
262 inner: Lock<HandlerInner>,
263 }
264
265 /// This inner struct exists to keep it all behind a single lock;
266 /// this is done to prevent possible deadlocks in a multi-threaded compiler,
267 /// as well as inconsistent state observation.
268 struct HandlerInner {
269 flags: HandlerFlags,
270 /// The number of errors that have been emitted, including duplicates.
271 ///
272 /// This is not necessarily the count that's reported to the user once
273 /// compilation ends.
274 err_count: usize,
275 warn_count: usize,
276 deduplicated_err_count: usize,
277 emitter: Box<dyn Emitter + sync::Send>,
278 delayed_span_bugs: Vec<Diagnostic>,
279 delayed_good_path_bugs: Vec<Diagnostic>,
280
281 /// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
282 /// emitting the same diagnostic with extended help (`--teach`) twice, which
283 /// would be uneccessary repetition.
284 taught_diagnostics: FxHashSet<DiagnosticId>,
285
286 /// Used to suggest rustc --explain <error code>
287 emitted_diagnostic_codes: FxHashSet<DiagnosticId>,
288
289 /// This set contains a hash of every diagnostic that has been emitted by
290 /// this handler. These hashes is used to avoid emitting the same error
291 /// twice.
292 emitted_diagnostics: FxHashSet<u128>,
293
294 /// Stashed diagnostics emitted in one stage of the compiler that may be
295 /// stolen by other stages (e.g. to improve them and add more information).
296 /// The stashed diagnostics count towards the total error count.
297 /// When `.abort_if_errors()` is called, these are also emitted.
298 stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>,
299
300 /// The warning count, used for a recap upon finishing
301 deduplicated_warn_count: usize,
302
303 future_breakage_diagnostics: Vec<Diagnostic>,
304 }
305
306 /// A key denoting where from a diagnostic was stashed.
307 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
308 pub enum StashKey {
309 ItemNoType,
310 }
311
312 fn default_track_diagnostic(_: &Diagnostic) {}
313
314 pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&Diagnostic)> =
315 AtomicRef::new(&(default_track_diagnostic as fn(&_)));
316
317 #[derive(Copy, Clone, Default)]
318 pub struct HandlerFlags {
319 /// If false, warning-level lints are suppressed.
320 /// (rustc: see `--allow warnings` and `--cap-lints`)
321 pub can_emit_warnings: bool,
322 /// If true, error-level diagnostics are upgraded to bug-level.
323 /// (rustc: see `-Z treat-err-as-bug`)
324 pub treat_err_as_bug: Option<usize>,
325 /// If true, immediately emit diagnostics that would otherwise be buffered.
326 /// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`)
327 pub dont_buffer_diagnostics: bool,
328 /// If true, immediately print bugs registered with `delay_span_bug`.
329 /// (rustc: see `-Z report-delayed-bugs`)
330 pub report_delayed_bugs: bool,
331 /// Show macro backtraces.
332 /// (rustc: see `-Z macro-backtrace`)
333 pub macro_backtrace: bool,
334 /// If true, identical diagnostics are reported only once.
335 pub deduplicate_diagnostics: bool,
336 }
337
338 impl Drop for HandlerInner {
339 fn drop(&mut self) {
340 self.emit_stashed_diagnostics();
341
342 if !self.has_errors() {
343 let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new());
344 self.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued");
345 }
346
347 if !self.has_any_message() {
348 let bugs = std::mem::replace(&mut self.delayed_good_path_bugs, Vec::new());
349 self.flush_delayed(
350 bugs,
351 "no warnings or errors encountered even though `delayed_good_path_bugs` issued",
352 );
353 }
354 }
355 }
356
357 impl Handler {
358 pub fn with_tty_emitter(
359 color_config: ColorConfig,
360 can_emit_warnings: bool,
361 treat_err_as_bug: Option<usize>,
362 sm: Option<Lrc<SourceMap>>,
363 ) -> Self {
364 Self::with_tty_emitter_and_flags(
365 color_config,
366 sm,
367 HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default::default() },
368 )
369 }
370
371 pub fn with_tty_emitter_and_flags(
372 color_config: ColorConfig,
373 sm: Option<Lrc<SourceMap>>,
374 flags: HandlerFlags,
375 ) -> Self {
376 let emitter = Box::new(EmitterWriter::stderr(
377 color_config,
378 sm,
379 false,
380 false,
381 None,
382 flags.macro_backtrace,
383 ));
384 Self::with_emitter_and_flags(emitter, flags)
385 }
386
387 pub fn with_emitter(
388 can_emit_warnings: bool,
389 treat_err_as_bug: Option<usize>,
390 emitter: Box<dyn Emitter + sync::Send>,
391 ) -> Self {
392 Handler::with_emitter_and_flags(
393 emitter,
394 HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default::default() },
395 )
396 }
397
398 pub fn with_emitter_and_flags(
399 emitter: Box<dyn Emitter + sync::Send>,
400 flags: HandlerFlags,
401 ) -> Self {
402 Self {
403 flags,
404 inner: Lock::new(HandlerInner {
405 flags,
406 err_count: 0,
407 warn_count: 0,
408 deduplicated_err_count: 0,
409 deduplicated_warn_count: 0,
410 emitter,
411 delayed_span_bugs: Vec::new(),
412 delayed_good_path_bugs: Vec::new(),
413 taught_diagnostics: Default::default(),
414 emitted_diagnostic_codes: Default::default(),
415 emitted_diagnostics: Default::default(),
416 stashed_diagnostics: Default::default(),
417 future_breakage_diagnostics: Vec::new(),
418 }),
419 }
420 }
421
422 // This is here to not allow mutation of flags;
423 // as of this writing it's only used in tests in librustc_middle.
424 pub fn can_emit_warnings(&self) -> bool {
425 self.flags.can_emit_warnings
426 }
427
428 /// Resets the diagnostic error count as well as the cached emitted diagnostics.
429 ///
430 /// NOTE: *do not* call this function from rustc. It is only meant to be called from external
431 /// tools that want to reuse a `Parser` cleaning the previously emitted diagnostics as well as
432 /// the overall count of emitted error diagnostics.
433 pub fn reset_err_count(&self) {
434 let mut inner = self.inner.borrow_mut();
435 inner.err_count = 0;
436 inner.warn_count = 0;
437 inner.deduplicated_err_count = 0;
438 inner.deduplicated_warn_count = 0;
439
440 // actually free the underlying memory (which `clear` would not do)
441 inner.delayed_span_bugs = Default::default();
442 inner.delayed_good_path_bugs = Default::default();
443 inner.taught_diagnostics = Default::default();
444 inner.emitted_diagnostic_codes = Default::default();
445 inner.emitted_diagnostics = Default::default();
446 inner.stashed_diagnostics = Default::default();
447 }
448
449 /// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing.
450 pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
451 let mut inner = self.inner.borrow_mut();
452 // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
453 // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key.
454 // See the PR for a discussion.
455 inner.stashed_diagnostics.insert((span, key), diag);
456 }
457
458 /// Steal a previously stashed diagnostic with the given `Span` and `StashKey` as the key.
459 pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_>> {
460 self.inner
461 .borrow_mut()
462 .stashed_diagnostics
463 .remove(&(span, key))
464 .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
465 }
466
467 /// Emit all stashed diagnostics.
468 pub fn emit_stashed_diagnostics(&self) {
469 self.inner.borrow_mut().emit_stashed_diagnostics();
470 }
471
472 /// Construct a dummy builder with `Level::Cancelled`.
473 ///
474 /// Using this will neither report anything to the user (e.g. a warning),
475 /// nor will compilation cancel as a result.
476 pub fn struct_dummy(&self) -> DiagnosticBuilder<'_> {
477 DiagnosticBuilder::new(self, Level::Cancelled, "")
478 }
479
480 /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
481 pub fn struct_span_warn(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> {
482 let mut result = self.struct_warn(msg);
483 result.set_span(span);
484 result
485 }
486
487 /// Construct a builder at the `Allow` level at the given `span` and with the `msg`.
488 pub fn struct_span_allow(
489 &self,
490 span: impl Into<MultiSpan>,
491 msg: &str,
492 ) -> DiagnosticBuilder<'_> {
493 let mut result = self.struct_allow(msg);
494 result.set_span(span);
495 result
496 }
497
498 /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
499 /// Also include a code.
500 pub fn struct_span_warn_with_code(
501 &self,
502 span: impl Into<MultiSpan>,
503 msg: &str,
504 code: DiagnosticId,
505 ) -> DiagnosticBuilder<'_> {
506 let mut result = self.struct_span_warn(span, msg);
507 result.code(code);
508 result
509 }
510
511 /// Construct a builder at the `Warning` level with the `msg`.
512 pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_> {
513 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
514 if !self.flags.can_emit_warnings {
515 result.cancel();
516 }
517 result
518 }
519
520 /// Construct a builder at the `Allow` level with the `msg`.
521 pub fn struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_> {
522 DiagnosticBuilder::new(self, Level::Allow, msg)
523 }
524
525 /// Construct a builder at the `Error` level at the given `span` and with the `msg`.
526 pub fn struct_span_err(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> {
527 let mut result = self.struct_err(msg);
528 result.set_span(span);
529 result
530 }
531
532 /// Construct a builder at the `Error` level at the given `span`, with the `msg`, and `code`.
533 pub fn struct_span_err_with_code(
534 &self,
535 span: impl Into<MultiSpan>,
536 msg: &str,
537 code: DiagnosticId,
538 ) -> DiagnosticBuilder<'_> {
539 let mut result = self.struct_span_err(span, msg);
540 result.code(code);
541 result
542 }
543
544 /// Construct a builder at the `Error` level with the `msg`.
545 // FIXME: This method should be removed (every error should have an associated error code).
546 pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_> {
547 DiagnosticBuilder::new(self, Level::Error, msg)
548 }
549
550 /// Construct a builder at the `Error` level with the `msg` and the `code`.
551 pub fn struct_err_with_code(&self, msg: &str, code: DiagnosticId) -> DiagnosticBuilder<'_> {
552 let mut result = self.struct_err(msg);
553 result.code(code);
554 result
555 }
556
557 /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`.
558 pub fn struct_span_fatal(
559 &self,
560 span: impl Into<MultiSpan>,
561 msg: &str,
562 ) -> DiagnosticBuilder<'_> {
563 let mut result = self.struct_fatal(msg);
564 result.set_span(span);
565 result
566 }
567
568 /// Construct a builder at the `Fatal` level at the given `span`, with the `msg`, and `code`.
569 pub fn struct_span_fatal_with_code(
570 &self,
571 span: impl Into<MultiSpan>,
572 msg: &str,
573 code: DiagnosticId,
574 ) -> DiagnosticBuilder<'_> {
575 let mut result = self.struct_span_fatal(span, msg);
576 result.code(code);
577 result
578 }
579
580 /// Construct a builder at the `Error` level with the `msg`.
581 pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_> {
582 DiagnosticBuilder::new(self, Level::Fatal, msg)
583 }
584
585 /// Construct a builder at the `Help` level with the `msg`.
586 pub fn struct_help(&self, msg: &str) -> DiagnosticBuilder<'_> {
587 DiagnosticBuilder::new(self, Level::Help, msg)
588 }
589
590 /// Construct a builder at the `Note` level with the `msg`.
591 pub fn struct_note_without_error(&self, msg: &str) -> DiagnosticBuilder<'_> {
592 DiagnosticBuilder::new(self, Level::Note, msg)
593 }
594
595 pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: &str) -> FatalError {
596 self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span);
597 FatalError
598 }
599
600 pub fn span_fatal_with_code(
601 &self,
602 span: impl Into<MultiSpan>,
603 msg: &str,
604 code: DiagnosticId,
605 ) -> FatalError {
606 self.emit_diag_at_span(Diagnostic::new_with_code(Fatal, Some(code), msg), span);
607 FatalError
608 }
609
610 pub fn span_err(&self, span: impl Into<MultiSpan>, msg: &str) {
611 self.emit_diag_at_span(Diagnostic::new(Error, msg), span);
612 }
613
614 pub fn span_err_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
615 self.emit_diag_at_span(Diagnostic::new_with_code(Error, Some(code), msg), span);
616 }
617
618 pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: &str) {
619 self.emit_diag_at_span(Diagnostic::new(Warning, msg), span);
620 }
621
622 pub fn span_warn_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
623 self.emit_diag_at_span(Diagnostic::new_with_code(Warning, Some(code), msg), span);
624 }
625
626 pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: &str) -> ! {
627 self.inner.borrow_mut().span_bug(span, msg)
628 }
629
630 #[track_caller]
631 pub fn delay_span_bug(&self, span: impl Into<MultiSpan>, msg: &str) {
632 self.inner.borrow_mut().delay_span_bug(span, msg)
633 }
634
635 pub fn delay_good_path_bug(&self, msg: &str) {
636 self.inner.borrow_mut().delay_good_path_bug(msg)
637 }
638
639 pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: &str) {
640 self.emit_diag_at_span(Diagnostic::new(Bug, msg), span);
641 }
642
643 pub fn span_note_without_error(&self, span: impl Into<MultiSpan>, msg: &str) {
644 self.emit_diag_at_span(Diagnostic::new(Note, msg), span);
645 }
646
647 pub fn span_note_diag(&self, span: Span, msg: &str) -> DiagnosticBuilder<'_> {
648 let mut db = DiagnosticBuilder::new(self, Note, msg);
649 db.set_span(span);
650 db
651 }
652
653 pub fn failure(&self, msg: &str) {
654 self.inner.borrow_mut().failure(msg);
655 }
656
657 pub fn fatal(&self, msg: &str) -> FatalError {
658 self.inner.borrow_mut().fatal(msg)
659 }
660
661 pub fn err(&self, msg: &str) {
662 self.inner.borrow_mut().err(msg);
663 }
664
665 pub fn warn(&self, msg: &str) {
666 let mut db = DiagnosticBuilder::new(self, Warning, msg);
667 db.emit();
668 }
669
670 pub fn note_without_error(&self, msg: &str) {
671 DiagnosticBuilder::new(self, Note, msg).emit();
672 }
673
674 pub fn bug(&self, msg: &str) -> ! {
675 self.inner.borrow_mut().bug(msg)
676 }
677
678 pub fn err_count(&self) -> usize {
679 self.inner.borrow().err_count()
680 }
681
682 pub fn has_errors(&self) -> bool {
683 self.inner.borrow().has_errors()
684 }
685 pub fn has_errors_or_delayed_span_bugs(&self) -> bool {
686 self.inner.borrow().has_errors_or_delayed_span_bugs()
687 }
688
689 pub fn print_error_count(&self, registry: &Registry) {
690 self.inner.borrow_mut().print_error_count(registry)
691 }
692
693 pub fn take_future_breakage_diagnostics(&self) -> Vec<Diagnostic> {
694 std::mem::take(&mut self.inner.borrow_mut().future_breakage_diagnostics)
695 }
696
697 pub fn abort_if_errors(&self) {
698 self.inner.borrow_mut().abort_if_errors()
699 }
700
701 /// `true` if we haven't taught a diagnostic with this code already.
702 /// The caller must then teach the user about such a diagnostic.
703 ///
704 /// Used to suppress emitting the same error multiple times with extended explanation when
705 /// calling `-Zteach`.
706 pub fn must_teach(&self, code: &DiagnosticId) -> bool {
707 self.inner.borrow_mut().must_teach(code)
708 }
709
710 pub fn force_print_diagnostic(&self, db: Diagnostic) {
711 self.inner.borrow_mut().force_print_diagnostic(db)
712 }
713
714 pub fn emit_diagnostic(&self, diagnostic: &Diagnostic) {
715 self.inner.borrow_mut().emit_diagnostic(diagnostic)
716 }
717
718 fn emit_diag_at_span(&self, mut diag: Diagnostic, sp: impl Into<MultiSpan>) {
719 let mut inner = self.inner.borrow_mut();
720 inner.emit_diagnostic(diag.set_span(sp));
721 }
722
723 pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
724 self.inner.borrow_mut().emit_artifact_notification(path, artifact_type)
725 }
726
727 pub fn emit_future_breakage_report(&self, diags: Vec<(FutureBreakage, Diagnostic)>) {
728 self.inner.borrow_mut().emitter.emit_future_breakage_report(diags)
729 }
730
731 pub fn delay_as_bug(&self, diagnostic: Diagnostic) {
732 self.inner.borrow_mut().delay_as_bug(diagnostic)
733 }
734 }
735
736 impl HandlerInner {
737 fn must_teach(&mut self, code: &DiagnosticId) -> bool {
738 self.taught_diagnostics.insert(code.clone())
739 }
740
741 fn force_print_diagnostic(&mut self, db: Diagnostic) {
742 self.emitter.emit_diagnostic(&db);
743 }
744
745 /// Emit all stashed diagnostics.
746 fn emit_stashed_diagnostics(&mut self) {
747 let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::<Vec<_>>();
748 diags.iter().for_each(|diag| self.emit_diagnostic(diag));
749 }
750
751 fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
752 if diagnostic.cancelled() {
753 return;
754 }
755
756 if diagnostic.has_future_breakage() {
757 self.future_breakage_diagnostics.push(diagnostic.clone());
758 }
759
760 if diagnostic.level == Warning && !self.flags.can_emit_warnings {
761 if diagnostic.has_future_breakage() {
762 (*TRACK_DIAGNOSTICS)(diagnostic);
763 }
764 return;
765 }
766
767 (*TRACK_DIAGNOSTICS)(diagnostic);
768
769 if diagnostic.level == Allow {
770 return;
771 }
772
773 if let Some(ref code) = diagnostic.code {
774 self.emitted_diagnostic_codes.insert(code.clone());
775 }
776
777 let already_emitted = |this: &mut Self| {
778 use std::hash::Hash;
779 let mut hasher = StableHasher::new();
780 diagnostic.hash(&mut hasher);
781 let diagnostic_hash = hasher.finish();
782 !this.emitted_diagnostics.insert(diagnostic_hash)
783 };
784
785 // Only emit the diagnostic if we've been asked to deduplicate and
786 // haven't already emitted an equivalent diagnostic.
787 if !(self.flags.deduplicate_diagnostics && already_emitted(self)) {
788 self.emitter.emit_diagnostic(diagnostic);
789 if diagnostic.is_error() {
790 self.deduplicated_err_count += 1;
791 } else if diagnostic.level == Warning {
792 self.deduplicated_warn_count += 1;
793 }
794 }
795 if diagnostic.is_error() {
796 self.bump_err_count();
797 } else {
798 self.bump_warn_count();
799 }
800 }
801
802 fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {
803 self.emitter.emit_artifact_notification(path, artifact_type);
804 }
805
806 fn treat_err_as_bug(&self) -> bool {
807 self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c)
808 }
809
810 fn print_error_count(&mut self, registry: &Registry) {
811 self.emit_stashed_diagnostics();
812
813 let warnings = match self.deduplicated_warn_count {
814 0 => String::new(),
815 1 => "1 warning emitted".to_string(),
816 count => format!("{} warnings emitted", count),
817 };
818 let errors = match self.deduplicated_err_count {
819 0 => String::new(),
820 1 => "aborting due to previous error".to_string(),
821 count => format!("aborting due to {} previous errors", count),
822 };
823 if self.treat_err_as_bug() {
824 return;
825 }
826
827 match (errors.len(), warnings.len()) {
828 (0, 0) => return,
829 (0, _) => self.emit_diagnostic(&Diagnostic::new(Level::Warning, &warnings)),
830 (_, 0) => {
831 let _ = self.fatal(&errors);
832 }
833 (_, _) => {
834 let _ = self.fatal(&format!("{}; {}", &errors, &warnings));
835 }
836 }
837
838 let can_show_explain = self.emitter.should_show_explain();
839 let are_there_diagnostics = !self.emitted_diagnostic_codes.is_empty();
840 if can_show_explain && are_there_diagnostics {
841 let mut error_codes = self
842 .emitted_diagnostic_codes
843 .iter()
844 .filter_map(|x| match &x {
845 DiagnosticId::Error(s) => {
846 if let Ok(Some(_explanation)) = registry.try_find_description(s) {
847 Some(s.clone())
848 } else {
849 None
850 }
851 }
852 _ => None,
853 })
854 .collect::<Vec<_>>();
855 if !error_codes.is_empty() {
856 error_codes.sort();
857 if error_codes.len() > 1 {
858 let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
859 self.failure(&format!(
860 "Some errors have detailed explanations: {}{}",
861 error_codes[..limit].join(", "),
862 if error_codes.len() > 9 { "..." } else { "." }
863 ));
864 self.failure(&format!(
865 "For more information about an error, try \
866 `rustc --explain {}`.",
867 &error_codes[0]
868 ));
869 } else {
870 self.failure(&format!(
871 "For more information about this error, try \
872 `rustc --explain {}`.",
873 &error_codes[0]
874 ));
875 }
876 }
877 }
878 }
879
880 fn err_count(&self) -> usize {
881 self.err_count + self.stashed_diagnostics.len()
882 }
883
884 fn has_errors(&self) -> bool {
885 self.err_count() > 0
886 }
887 fn has_errors_or_delayed_span_bugs(&self) -> bool {
888 self.has_errors() || !self.delayed_span_bugs.is_empty()
889 }
890 fn has_any_message(&self) -> bool {
891 self.err_count() > 0 || self.warn_count > 0
892 }
893
894 fn abort_if_errors(&mut self) {
895 self.emit_stashed_diagnostics();
896
897 if self.has_errors() {
898 FatalError.raise();
899 }
900 }
901
902 fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> ! {
903 self.emit_diag_at_span(Diagnostic::new(Bug, msg), sp);
904 panic::panic_any(ExplicitBug);
905 }
906
907 fn emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into<MultiSpan>) {
908 self.emit_diagnostic(diag.set_span(sp));
909 }
910
911 #[track_caller]
912 fn delay_span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) {
913 // This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
914 // incrementing `err_count` by one, so we need to +1 the comparing.
915 // FIXME: Would be nice to increment err_count in a more coherent way.
916 if self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() + 1 >= c) {
917 // FIXME: don't abort here if report_delayed_bugs is off
918 self.span_bug(sp, msg);
919 }
920 let mut diagnostic = Diagnostic::new(Level::Bug, msg);
921 diagnostic.set_span(sp.into());
922 diagnostic.note(&format!("delayed at {}", std::panic::Location::caller()));
923 self.delay_as_bug(diagnostic)
924 }
925
926 fn delay_good_path_bug(&mut self, msg: &str) {
927 let mut diagnostic = Diagnostic::new(Level::Bug, msg);
928 if self.flags.report_delayed_bugs {
929 self.emit_diagnostic(&diagnostic);
930 }
931 diagnostic.note(&format!("delayed at {}", std::backtrace::Backtrace::force_capture()));
932 self.delayed_good_path_bugs.push(diagnostic);
933 }
934
935 fn failure(&mut self, msg: &str) {
936 self.emit_diagnostic(&Diagnostic::new(FailureNote, msg));
937 }
938
939 fn fatal(&mut self, msg: &str) -> FatalError {
940 self.emit_error(Fatal, msg);
941 FatalError
942 }
943
944 fn err(&mut self, msg: &str) {
945 self.emit_error(Error, msg);
946 }
947
948 /// Emit an error; level should be `Error` or `Fatal`.
949 fn emit_error(&mut self, level: Level, msg: &str) {
950 if self.treat_err_as_bug() {
951 self.bug(msg);
952 }
953 self.emit_diagnostic(&Diagnostic::new(level, msg));
954 }
955
956 fn bug(&mut self, msg: &str) -> ! {
957 self.emit_diagnostic(&Diagnostic::new(Bug, msg));
958 panic::panic_any(ExplicitBug);
959 }
960
961 fn delay_as_bug(&mut self, diagnostic: Diagnostic) {
962 if self.flags.report_delayed_bugs {
963 self.emit_diagnostic(&diagnostic);
964 }
965 self.delayed_span_bugs.push(diagnostic);
966 }
967
968 fn flush_delayed(&mut self, bugs: Vec<Diagnostic>, explanation: &str) {
969 let has_bugs = !bugs.is_empty();
970 for bug in bugs {
971 self.emit_diagnostic(&bug);
972 }
973 if has_bugs {
974 panic!("{}", explanation);
975 }
976 }
977
978 fn bump_err_count(&mut self) {
979 self.err_count += 1;
980 self.panic_if_treat_err_as_bug();
981 }
982
983 fn bump_warn_count(&mut self) {
984 self.warn_count += 1;
985 }
986
987 fn panic_if_treat_err_as_bug(&self) {
988 if self.treat_err_as_bug() {
989 match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) {
990 (1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
991 (0, _) | (1, _) => {}
992 (count, as_bug) => panic!(
993 "aborting after {} errors due to `-Z treat-err-as-bug={}`",
994 count, as_bug,
995 ),
996 }
997 }
998 }
999 }
1000
1001 #[derive(Copy, PartialEq, Clone, Hash, Debug, Encodable, Decodable)]
1002 pub enum Level {
1003 Bug,
1004 Fatal,
1005 Error,
1006 Warning,
1007 Note,
1008 Help,
1009 Cancelled,
1010 FailureNote,
1011 Allow,
1012 }
1013
1014 impl fmt::Display for Level {
1015 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1016 self.to_str().fmt(f)
1017 }
1018 }
1019
1020 impl Level {
1021 fn color(self) -> ColorSpec {
1022 let mut spec = ColorSpec::new();
1023 match self {
1024 Bug | Fatal | Error => {
1025 spec.set_fg(Some(Color::Red)).set_intense(true);
1026 }
1027 Warning => {
1028 spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
1029 }
1030 Note => {
1031 spec.set_fg(Some(Color::Green)).set_intense(true);
1032 }
1033 Help => {
1034 spec.set_fg(Some(Color::Cyan)).set_intense(true);
1035 }
1036 FailureNote => {}
1037 Allow | Cancelled => unreachable!(),
1038 }
1039 spec
1040 }
1041
1042 pub fn to_str(self) -> &'static str {
1043 match self {
1044 Bug => "error: internal compiler error",
1045 Fatal | Error => "error",
1046 Warning => "warning",
1047 Note => "note",
1048 Help => "help",
1049 FailureNote => "failure-note",
1050 Cancelled => panic!("Shouldn't call on cancelled error"),
1051 Allow => panic!("Shouldn't call on allowed error"),
1052 }
1053 }
1054
1055 pub fn is_failure_note(&self) -> bool {
1056 matches!(*self, FailureNote)
1057 }
1058 }
1059
1060 pub fn add_elided_lifetime_in_path_suggestion(
1061 source_map: &SourceMap,
1062 db: &mut DiagnosticBuilder<'_>,
1063 n: usize,
1064 path_span: Span,
1065 incl_angl_brckt: bool,
1066 insertion_span: Span,
1067 anon_lts: String,
1068 ) {
1069 let (replace_span, suggestion) = if incl_angl_brckt {
1070 (insertion_span, anon_lts)
1071 } else {
1072 // When possible, prefer a suggestion that replaces the whole
1073 // `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
1074 // at a point (which makes for an ugly/confusing label)
1075 if let Ok(snippet) = source_map.span_to_snippet(path_span) {
1076 // But our spans can get out of whack due to macros; if the place we think
1077 // we want to insert `'_` isn't even within the path expression's span, we
1078 // should bail out of making any suggestion rather than panicking on a
1079 // subtract-with-overflow or string-slice-out-out-bounds (!)
1080 // FIXME: can we do better?
1081 if insertion_span.lo().0 < path_span.lo().0 {
1082 return;
1083 }
1084 let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
1085 if insertion_index > snippet.len() {
1086 return;
1087 }
1088 let (before, after) = snippet.split_at(insertion_index);
1089 (path_span, format!("{}{}{}", before, anon_lts, after))
1090 } else {
1091 (insertion_span, anon_lts)
1092 }
1093 };
1094 db.span_suggestion(
1095 replace_span,
1096 &format!("indicate the anonymous lifetime{}", pluralize!(n)),
1097 suggestion,
1098 Applicability::MachineApplicable,
1099 );
1100 }
1101
1102 // Useful type to use with `Result<>` indicate that an error has already
1103 // been reported to the user, so no need to continue checking.
1104 #[derive(Clone, Copy, Debug, Encodable, Decodable, Hash, PartialEq, Eq)]
1105 pub struct ErrorReported;
1106
1107 rustc_data_structures::impl_stable_hash_via_hash!(ErrorReported);