]> git.lizzy.rs Git - rust.git/blob - src/librustc_errors/lib.rs
Rollup merge of #58145 - taiki-e:poll, r=cramertj
[rust.git] / src / librustc_errors / lib.rs
1 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
2       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
3       html_root_url = "https://doc.rust-lang.org/nightly/")]
4
5 #![feature(custom_attribute)]
6 #![allow(unused_attributes)]
7 #![feature(range_contains)]
8 #![cfg_attr(unix, feature(libc))]
9 #![feature(nll)]
10 #![feature(optin_builtin_traits)]
11
12 extern crate atty;
13 extern crate termcolor;
14 #[cfg(unix)]
15 extern crate libc;
16 #[macro_use]
17 extern crate log;
18 extern crate rustc_data_structures;
19 extern crate serialize as rustc_serialize;
20 extern crate syntax_pos;
21 extern crate unicode_width;
22
23 pub use emitter::ColorConfig;
24
25 use self::Level::*;
26
27 use emitter::{Emitter, EmitterWriter};
28
29 use rustc_data_structures::sync::{self, Lrc, Lock, AtomicUsize, AtomicBool, SeqCst};
30 use rustc_data_structures::fx::FxHashSet;
31 use rustc_data_structures::stable_hasher::StableHasher;
32
33 use std::borrow::Cow;
34 use std::cell::Cell;
35 use std::{error, fmt};
36 use std::panic;
37
38 use termcolor::{ColorSpec, Color};
39
40 mod diagnostic;
41 mod diagnostic_builder;
42 pub mod emitter;
43 mod snippet;
44 pub mod registry;
45 mod styled_buffer;
46 mod lock;
47
48 use syntax_pos::{BytePos,
49                  Loc,
50                  FileLinesResult,
51                  SourceFile,
52                  FileName,
53                  MultiSpan,
54                  Span,
55                  NO_EXPANSION};
56
57 /// Indicates the confidence in the correctness of a suggestion.
58 ///
59 /// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion
60 /// to determine whether it should be automatically applied or if the user should be consulted
61 /// before applying the suggestion.
62 #[derive(Copy, Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
63 pub enum Applicability {
64     /// The suggestion is definitely what the user intended. This suggestion should be
65     /// automatically applied.
66     MachineApplicable,
67
68     /// The suggestion may be what the user intended, but it is uncertain. The suggestion should
69     /// result in valid Rust code if it is applied.
70     MaybeIncorrect,
71
72     /// The suggestion contains placeholders like `(...)` or `{ /* fields */ }`. The suggestion
73     /// cannot be applied automatically because it will not result in valid Rust code. The user
74     /// will need to fill in the placeholders.
75     HasPlaceholders,
76
77     /// The applicability of the suggestion is unknown.
78     Unspecified,
79 }
80
81 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
82 pub struct CodeSuggestion {
83     /// Each substitute can have multiple variants due to multiple
84     /// applicable suggestions
85     ///
86     /// `foo.bar` might be replaced with `a.b` or `x.y` by replacing
87     /// `foo` and `bar` on their own:
88     ///
89     /// ```
90     /// vec![
91     ///     Substitution { parts: vec![(0..3, "a"), (4..7, "b")] },
92     ///     Substitution { parts: vec![(0..3, "x"), (4..7, "y")] },
93     /// ]
94     /// ```
95     ///
96     /// or by replacing the entire span:
97     ///
98     /// ```
99     /// vec![
100     ///     Substitution { parts: vec![(0..7, "a.b")] },
101     ///     Substitution { parts: vec![(0..7, "x.y")] },
102     /// ]
103     /// ```
104     pub substitutions: Vec<Substitution>,
105     pub msg: String,
106     pub show_code_when_inline: bool,
107     /// Whether or not the suggestion is approximate
108     ///
109     /// Sometimes we may show suggestions with placeholders,
110     /// which are useful for users but not useful for
111     /// tools like rustfix
112     pub applicability: Applicability,
113 }
114
115 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
116 /// See the docs on `CodeSuggestion::substitutions`
117 pub struct Substitution {
118     pub parts: Vec<SubstitutionPart>,
119 }
120
121 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
122 pub struct SubstitutionPart {
123     pub span: Span,
124     pub snippet: String,
125 }
126
127 pub type SourceMapperDyn = dyn SourceMapper + sync::Send + sync::Sync;
128
129 pub trait SourceMapper {
130     fn lookup_char_pos(&self, pos: BytePos) -> Loc;
131     fn span_to_lines(&self, sp: Span) -> FileLinesResult;
132     fn span_to_string(&self, sp: Span) -> String;
133     fn span_to_filename(&self, sp: Span) -> FileName;
134     fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
135     fn call_span_if_macro(&self, sp: Span) -> Span;
136     fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool;
137     fn doctest_offset_line(&self, file: &FileName, line: usize) -> usize;
138 }
139
140 impl CodeSuggestion {
141     /// Returns the assembled code suggestions and whether they should be shown with an underline.
142     pub fn splice_lines(&self, cm: &SourceMapperDyn)
143                         -> Vec<(String, Vec<SubstitutionPart>)> {
144         use syntax_pos::{CharPos, Loc, Pos};
145
146         fn push_trailing(buf: &mut String,
147                          line_opt: Option<&Cow<str>>,
148                          lo: &Loc,
149                          hi_opt: Option<&Loc>) {
150             let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
151             if let Some(line) = line_opt {
152                 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
153                     let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
154                     match hi_opt {
155                         Some(hi) if hi > lo => buf.push_str(&line[lo..hi]),
156                         Some(_) => (),
157                         None => buf.push_str(&line[lo..]),
158                     }
159                 }
160                 if let None = hi_opt {
161                     buf.push('\n');
162                 }
163             }
164         }
165
166         assert!(!self.substitutions.is_empty());
167
168         self.substitutions.iter().cloned().map(|mut substitution| {
169             // Assumption: all spans are in the same file, and all spans
170             // are disjoint. Sort in ascending order.
171             substitution.parts.sort_by_key(|part| part.span.lo());
172
173             // Find the bounding span.
174             let lo = substitution.parts.iter().map(|part| part.span.lo()).min().unwrap();
175             let hi = substitution.parts.iter().map(|part| part.span.hi()).min().unwrap();
176             let bounding_span = Span::new(lo, hi, NO_EXPANSION);
177             let lines = cm.span_to_lines(bounding_span).unwrap();
178             assert!(!lines.lines.is_empty());
179
180             // To build up the result, we do this for each span:
181             // - push the line segment trailing the previous span
182             //   (at the beginning a "phantom" span pointing at the start of the line)
183             // - push lines between the previous and current span (if any)
184             // - if the previous and current span are not on the same line
185             //   push the line segment leading up to the current span
186             // - splice in the span substitution
187             //
188             // Finally push the trailing line segment of the last span
189             let fm = &lines.file;
190             let mut prev_hi = cm.lookup_char_pos(bounding_span.lo());
191             prev_hi.col = CharPos::from_usize(0);
192
193             let mut prev_line = fm.get_line(lines.lines[0].line_index);
194             let mut buf = String::new();
195
196             for part in &substitution.parts {
197                 let cur_lo = cm.lookup_char_pos(part.span.lo());
198                 if prev_hi.line == cur_lo.line {
199                     push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
200                 } else {
201                     push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
202                     // push lines between the previous and current span (if any)
203                     for idx in prev_hi.line..(cur_lo.line - 1) {
204                         if let Some(line) = fm.get_line(idx) {
205                             buf.push_str(line.as_ref());
206                             buf.push('\n');
207                         }
208                     }
209                     if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
210                         buf.push_str(&cur_line[..cur_lo.col.to_usize()]);
211                     }
212                 }
213                 buf.push_str(&part.snippet);
214                 prev_hi = cm.lookup_char_pos(part.span.hi());
215                 prev_line = fm.get_line(prev_hi.line - 1);
216             }
217             // if the replacement already ends with a newline, don't print the next line
218             if !buf.ends_with('\n') {
219                 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
220             }
221             // remove trailing newlines
222             while buf.ends_with('\n') {
223                 buf.pop();
224             }
225             (buf, substitution.parts)
226         }).collect()
227     }
228 }
229
230 /// Used as a return value to signify a fatal error occurred. (It is also
231 /// used as the argument to panic at the moment, but that will eventually
232 /// not be true.)
233 #[derive(Copy, Clone, Debug)]
234 #[must_use]
235 pub struct FatalError;
236
237 pub struct FatalErrorMarker;
238
239 // Don't implement Send on FatalError. This makes it impossible to panic!(FatalError).
240 // We don't want to invoke the panic handler and print a backtrace for fatal errors.
241 impl !Send for FatalError {}
242
243 impl FatalError {
244     pub fn raise(self) -> ! {
245         panic::resume_unwind(Box::new(FatalErrorMarker))
246     }
247 }
248
249 impl fmt::Display for FatalError {
250     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
251         write!(f, "parser fatal error")
252     }
253 }
254
255 impl error::Error for FatalError {
256     fn description(&self) -> &str {
257         "The parser has encountered a fatal error"
258     }
259 }
260
261 /// Signifies that the compiler died with an explicit call to `.bug`
262 /// or `.span_bug` rather than a failed assertion, etc.
263 #[derive(Copy, Clone, Debug)]
264 pub struct ExplicitBug;
265
266 impl fmt::Display for ExplicitBug {
267     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
268         write!(f, "parser internal bug")
269     }
270 }
271
272 impl error::Error for ExplicitBug {
273     fn description(&self) -> &str {
274         "The parser has encountered an internal bug"
275     }
276 }
277
278 pub use diagnostic::{Diagnostic, SubDiagnostic, DiagnosticStyledString, DiagnosticId};
279 pub use diagnostic_builder::DiagnosticBuilder;
280
281 /// A handler deals with errors; certain errors
282 /// (fatal, bug, unimpl) may cause immediate exit,
283 /// others log errors for later reporting.
284 pub struct Handler {
285     pub flags: HandlerFlags,
286
287     err_count: AtomicUsize,
288     emitter: Lock<Box<dyn Emitter + sync::Send>>,
289     continue_after_error: AtomicBool,
290     delayed_span_bugs: Lock<Vec<Diagnostic>>,
291
292     // This set contains the `DiagnosticId` of all emitted diagnostics to avoid
293     // emitting the same diagnostic with extended help (`--teach`) twice, which
294     // would be uneccessary repetition.
295     taught_diagnostics: Lock<FxHashSet<DiagnosticId>>,
296
297     /// Used to suggest rustc --explain <error code>
298     emitted_diagnostic_codes: Lock<FxHashSet<DiagnosticId>>,
299
300     // This set contains a hash of every diagnostic that has been emitted by
301     // this handler. These hashes is used to avoid emitting the same error
302     // twice.
303     emitted_diagnostics: Lock<FxHashSet<u128>>,
304 }
305
306 fn default_track_diagnostic(_: &Diagnostic) {}
307
308 thread_local!(pub static TRACK_DIAGNOSTICS: Cell<fn(&Diagnostic)> =
309                 Cell::new(default_track_diagnostic));
310
311 #[derive(Default)]
312 pub struct HandlerFlags {
313     /// If false, warning-level lints are suppressed.
314     /// (rustc: see `--allow warnings` and `--cap-lints`)
315     pub can_emit_warnings: bool,
316     /// If true, error-level diagnostics are upgraded to bug-level.
317     /// (rustc: see `-Z treat-err-as-bug`)
318     pub treat_err_as_bug: bool,
319     /// If true, immediately emit diagnostics that would otherwise be buffered.
320     /// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`)
321     pub dont_buffer_diagnostics: bool,
322     /// If true, immediately print bugs registered with `delay_span_bug`.
323     /// (rustc: see `-Z report-delayed-bugs`)
324     pub report_delayed_bugs: bool,
325     /// show macro backtraces even for non-local macros.
326     /// (rustc: see `-Z external-macro-backtrace`)
327     pub external_macro_backtrace: bool,
328 }
329
330 impl Drop for Handler {
331     fn drop(&mut self) {
332         if self.err_count() == 0 {
333             let mut bugs = self.delayed_span_bugs.borrow_mut();
334             let has_bugs = !bugs.is_empty();
335             for bug in bugs.drain(..) {
336                 DiagnosticBuilder::new_diagnostic(self, bug).emit();
337             }
338             if has_bugs {
339                 panic!("no errors encountered even though `delay_span_bug` issued");
340             }
341         }
342     }
343 }
344
345 impl Handler {
346     pub fn with_tty_emitter(color_config: ColorConfig,
347                             can_emit_warnings: bool,
348                             treat_err_as_bug: bool,
349                             cm: Option<Lrc<SourceMapperDyn>>)
350                             -> Handler {
351         Handler::with_tty_emitter_and_flags(
352             color_config,
353             cm,
354             HandlerFlags {
355                 can_emit_warnings,
356                 treat_err_as_bug,
357                 .. Default::default()
358             })
359     }
360
361     pub fn with_tty_emitter_and_flags(color_config: ColorConfig,
362                                       cm: Option<Lrc<SourceMapperDyn>>,
363                                       flags: HandlerFlags)
364                                       -> Handler {
365         let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false));
366         Handler::with_emitter_and_flags(emitter, flags)
367     }
368
369     pub fn with_emitter(can_emit_warnings: bool,
370                         treat_err_as_bug: bool,
371                         e: Box<dyn Emitter + sync::Send>)
372                         -> Handler {
373         Handler::with_emitter_and_flags(
374             e,
375             HandlerFlags {
376                 can_emit_warnings,
377                 treat_err_as_bug,
378                 .. Default::default()
379             })
380     }
381
382     pub fn with_emitter_and_flags(e: Box<dyn Emitter + sync::Send>, flags: HandlerFlags) -> Handler
383     {
384         Handler {
385             flags,
386             err_count: AtomicUsize::new(0),
387             emitter: Lock::new(e),
388             continue_after_error: AtomicBool::new(true),
389             delayed_span_bugs: Lock::new(Vec::new()),
390             taught_diagnostics: Default::default(),
391             emitted_diagnostic_codes: Default::default(),
392             emitted_diagnostics: Default::default(),
393         }
394     }
395
396     pub fn set_continue_after_error(&self, continue_after_error: bool) {
397         self.continue_after_error.store(continue_after_error, SeqCst);
398     }
399
400     /// Resets the diagnostic error count as well as the cached emitted diagnostics.
401     ///
402     /// NOTE: DO NOT call this function from rustc. It is only meant to be called from external
403     /// tools that want to reuse a `Parser` cleaning the previously emitted diagnostics as well as
404     /// the overall count of emitted error diagnostics.
405     pub fn reset_err_count(&self) {
406         // actually frees the underlying memory (which `clear` would not do)
407         *self.emitted_diagnostics.borrow_mut() = Default::default();
408         self.err_count.store(0, SeqCst);
409     }
410
411     pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> {
412         DiagnosticBuilder::new(self, Level::Cancelled, "")
413     }
414
415     pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
416                                                     sp: S,
417                                                     msg: &str)
418                                                     -> DiagnosticBuilder<'a> {
419         let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
420         result.set_span(sp);
421         if !self.flags.can_emit_warnings {
422             result.cancel();
423         }
424         result
425     }
426     pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self,
427                                                               sp: S,
428                                                               msg: &str,
429                                                               code: DiagnosticId)
430                                                               -> DiagnosticBuilder<'a> {
431         let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
432         result.set_span(sp);
433         result.code(code);
434         if !self.flags.can_emit_warnings {
435             result.cancel();
436         }
437         result
438     }
439     pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
440         let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
441         if !self.flags.can_emit_warnings {
442             result.cancel();
443         }
444         result
445     }
446     pub fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
447                                                    sp: S,
448                                                    msg: &str)
449                                                    -> DiagnosticBuilder<'a> {
450         let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
451         result.set_span(sp);
452         result
453     }
454     pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
455                                                              sp: S,
456                                                              msg: &str,
457                                                              code: DiagnosticId)
458                                                              -> DiagnosticBuilder<'a> {
459         let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
460         result.set_span(sp);
461         result.code(code);
462         result
463     }
464     // FIXME: This method should be removed (every error should have an associated error code).
465     pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
466         DiagnosticBuilder::new(self, Level::Error, msg)
467     }
468     pub fn struct_err_with_code<'a>(
469         &'a self,
470         msg: &str,
471         code: DiagnosticId,
472     ) -> DiagnosticBuilder<'a> {
473         let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
474         result.code(code);
475         result
476     }
477     pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
478                                                      sp: S,
479                                                      msg: &str)
480                                                      -> DiagnosticBuilder<'a> {
481         let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
482         result.set_span(sp);
483         result
484     }
485     pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self,
486                                                                sp: S,
487                                                                msg: &str,
488                                                                code: DiagnosticId)
489                                                                -> DiagnosticBuilder<'a> {
490         let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
491         result.set_span(sp);
492         result.code(code);
493         result
494     }
495     pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
496         DiagnosticBuilder::new(self, Level::Fatal, msg)
497     }
498
499     pub fn cancel(&self, err: &mut DiagnosticBuilder) {
500         err.cancel();
501     }
502
503     fn panic_if_treat_err_as_bug(&self) {
504         if self.flags.treat_err_as_bug {
505             panic!("encountered error with `-Z treat_err_as_bug");
506         }
507     }
508
509     pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError {
510         self.emit(&sp.into(), msg, Fatal);
511         FatalError
512     }
513     pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self,
514                                                     sp: S,
515                                                     msg: &str,
516                                                     code: DiagnosticId)
517                                                     -> FatalError {
518         self.emit_with_code(&sp.into(), msg, code, Fatal);
519         FatalError
520     }
521     pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
522         self.emit(&sp.into(), msg, Error);
523     }
524     pub fn mut_span_err<'a, S: Into<MultiSpan>>(&'a self,
525                                                 sp: S,
526                                                 msg: &str)
527                                                 -> DiagnosticBuilder<'a> {
528         let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
529         result.set_span(sp);
530         result
531     }
532     pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
533         self.emit_with_code(&sp.into(), msg, code, Error);
534     }
535     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
536         self.emit(&sp.into(), msg, Warning);
537     }
538     pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
539         self.emit_with_code(&sp.into(), msg, code, Warning);
540     }
541     pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
542         self.emit(&sp.into(), msg, Bug);
543         panic!(ExplicitBug);
544     }
545     pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
546         if self.flags.treat_err_as_bug {
547             // FIXME: don't abort here if report_delayed_bugs is off
548             self.span_bug(sp, msg);
549         }
550         let mut diagnostic = Diagnostic::new(Level::Bug, msg);
551         diagnostic.set_span(sp.into());
552         self.delay_as_bug(diagnostic);
553     }
554     fn delay_as_bug(&self, diagnostic: Diagnostic) {
555         if self.flags.report_delayed_bugs {
556             DiagnosticBuilder::new_diagnostic(self, diagnostic.clone()).emit();
557         }
558         self.delayed_span_bugs.borrow_mut().push(diagnostic);
559     }
560     pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
561         self.emit(&sp.into(), msg, Bug);
562     }
563     pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
564         self.emit(&sp.into(), msg, Note);
565     }
566     pub fn span_note_diag<'a>(&'a self,
567                               sp: Span,
568                               msg: &str)
569                               -> DiagnosticBuilder<'a> {
570         let mut db = DiagnosticBuilder::new(self, Note, msg);
571         db.set_span(sp);
572         db
573     }
574     pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
575         self.span_bug(sp, &format!("unimplemented {}", msg));
576     }
577     pub fn failure(&self, msg: &str) {
578         DiagnosticBuilder::new(self, FailureNote, msg).emit()
579     }
580     pub fn fatal(&self, msg: &str) -> FatalError {
581         if self.flags.treat_err_as_bug {
582             self.bug(msg);
583         }
584         DiagnosticBuilder::new(self, Fatal, msg).emit();
585         FatalError
586     }
587     pub fn err(&self, msg: &str) {
588         if self.flags.treat_err_as_bug {
589             self.bug(msg);
590         }
591         let mut db = DiagnosticBuilder::new(self, Error, msg);
592         db.emit();
593     }
594     pub fn warn(&self, msg: &str) {
595         let mut db = DiagnosticBuilder::new(self, Warning, msg);
596         db.emit();
597     }
598     pub fn note_without_error(&self, msg: &str) {
599         let mut db = DiagnosticBuilder::new(self, Note, msg);
600         db.emit();
601     }
602     pub fn bug(&self, msg: &str) -> ! {
603         let mut db = DiagnosticBuilder::new(self, Bug, msg);
604         db.emit();
605         panic!(ExplicitBug);
606     }
607     pub fn unimpl(&self, msg: &str) -> ! {
608         self.bug(&format!("unimplemented {}", msg));
609     }
610
611     fn bump_err_count(&self) {
612         self.panic_if_treat_err_as_bug();
613         self.err_count.fetch_add(1, SeqCst);
614     }
615
616     pub fn err_count(&self) -> usize {
617         self.err_count.load(SeqCst)
618     }
619
620     pub fn has_errors(&self) -> bool {
621         self.err_count() > 0
622     }
623
624     pub fn print_error_count(&self) {
625         let s = match self.err_count() {
626             0 => return,
627             1 => "aborting due to previous error".to_string(),
628             _ => format!("aborting due to {} previous errors", self.err_count())
629         };
630
631         let _ = self.fatal(&s);
632
633         let can_show_explain = self.emitter.borrow().should_show_explain();
634         let are_there_diagnostics = !self.emitted_diagnostic_codes.borrow().is_empty();
635         if can_show_explain && are_there_diagnostics {
636             let mut error_codes =
637                 self.emitted_diagnostic_codes.borrow()
638                                              .iter()
639                                              .filter_map(|x| match *x {
640                                                  DiagnosticId::Error(ref s) => Some(s.clone()),
641                                                  _ => None,
642                                              })
643                                              .collect::<Vec<_>>();
644             if !error_codes.is_empty() {
645                 error_codes.sort();
646                 if error_codes.len() > 1 {
647                     let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
648                     self.failure(&format!("Some errors occurred: {}{}",
649                                           error_codes[..limit].join(", "),
650                                           if error_codes.len() > 9 { "..." } else { "." }));
651                     self.failure(&format!("For more information about an error, try \
652                                            `rustc --explain {}`.",
653                                           &error_codes[0]));
654                 } else {
655                     self.failure(&format!("For more information about this error, try \
656                                            `rustc --explain {}`.",
657                                           &error_codes[0]));
658                 }
659             }
660         }
661     }
662
663     pub fn abort_if_errors(&self) {
664         if self.err_count() == 0 {
665             return;
666         }
667         FatalError.raise();
668     }
669     pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) {
670         if lvl == Warning && !self.flags.can_emit_warnings {
671             return;
672         }
673         let mut db = DiagnosticBuilder::new(self, lvl, msg);
674         db.set_span(msp.clone());
675         db.emit();
676         if !self.continue_after_error.load(SeqCst) {
677             self.abort_if_errors();
678         }
679     }
680     pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: DiagnosticId, lvl: Level) {
681         if lvl == Warning && !self.flags.can_emit_warnings {
682             return;
683         }
684         let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code), msg);
685         db.set_span(msp.clone());
686         db.emit();
687         if !self.continue_after_error.load(SeqCst) {
688             self.abort_if_errors();
689         }
690     }
691
692     /// `true` if we haven't taught a diagnostic with this code already.
693     /// The caller must then teach the user about such a diagnostic.
694     ///
695     /// Used to suppress emitting the same error multiple times with extended explanation when
696     /// calling `-Zteach`.
697     pub fn must_teach(&self, code: &DiagnosticId) -> bool {
698         self.taught_diagnostics.borrow_mut().insert(code.clone())
699     }
700
701     pub fn force_print_db(&self, mut db: DiagnosticBuilder) {
702         self.emitter.borrow_mut().emit(&db);
703         db.cancel();
704     }
705
706     fn emit_db(&self, db: &DiagnosticBuilder) {
707         let diagnostic = &**db;
708
709         TRACK_DIAGNOSTICS.with(|track_diagnostics| {
710             track_diagnostics.get()(diagnostic);
711         });
712
713         if let Some(ref code) = diagnostic.code {
714             self.emitted_diagnostic_codes.borrow_mut().insert(code.clone());
715         }
716
717         let diagnostic_hash = {
718             use std::hash::Hash;
719             let mut hasher = StableHasher::new();
720             diagnostic.hash(&mut hasher);
721             hasher.finish()
722         };
723
724         // Only emit the diagnostic if we haven't already emitted an equivalent
725         // one:
726         if self.emitted_diagnostics.borrow_mut().insert(diagnostic_hash) {
727             self.emitter.borrow_mut().emit(db);
728             if db.is_error() {
729                 self.bump_err_count();
730             }
731         }
732     }
733 }
734
735
736 #[derive(Copy, PartialEq, Clone, Hash, Debug, RustcEncodable, RustcDecodable)]
737 pub enum Level {
738     Bug,
739     Fatal,
740     // An error which while not immediately fatal, should stop the compiler
741     // progressing beyond the current phase.
742     PhaseFatal,
743     Error,
744     Warning,
745     Note,
746     Help,
747     Cancelled,
748     FailureNote,
749 }
750
751 impl fmt::Display for Level {
752     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
753         self.to_str().fmt(f)
754     }
755 }
756
757 impl Level {
758     fn color(self) -> ColorSpec {
759         let mut spec = ColorSpec::new();
760         match self {
761             Bug | Fatal | PhaseFatal | Error => {
762                 spec.set_fg(Some(Color::Red))
763                     .set_intense(true);
764             }
765             Warning => {
766                 spec.set_fg(Some(Color::Yellow))
767                     .set_intense(cfg!(windows));
768             }
769             Note => {
770                 spec.set_fg(Some(Color::Green))
771                     .set_intense(true);
772             }
773             Help => {
774                 spec.set_fg(Some(Color::Cyan))
775                     .set_intense(true);
776             }
777             FailureNote => {}
778             Cancelled => unreachable!(),
779         }
780         spec
781     }
782
783     pub fn to_str(self) -> &'static str {
784         match self {
785             Bug => "error: internal compiler error",
786             Fatal | PhaseFatal | Error => "error",
787             Warning => "warning",
788             Note => "note",
789             Help => "help",
790             FailureNote => "",
791             Cancelled => panic!("Shouldn't call on cancelled error"),
792         }
793     }
794
795     pub fn is_failure_note(&self) -> bool {
796         match *self {
797             FailureNote => true,
798             _ => false,
799         }
800     }
801 }