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