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