1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
12 html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
13 html_root_url = "https://doc.rust-lang.org/nightly/")]
15 #![feature(custom_attribute)]
16 #![allow(unused_attributes)]
17 #![feature(range_contains)]
18 #![cfg_attr(unix, feature(libc))]
19 #![feature(optin_builtin_traits)]
22 extern crate termcolor;
25 extern crate rustc_data_structures;
26 extern crate serialize as rustc_serialize;
27 extern crate syntax_pos;
28 extern crate unicode_width;
30 pub use emitter::ColorConfig;
34 use emitter::{Emitter, EmitterWriter};
36 use rustc_data_structures::sync::{self, Lrc, Lock, LockCell};
37 use rustc_data_structures::fx::FxHashSet;
38 use rustc_data_structures::stable_hasher::StableHasher;
42 use std::{error, fmt};
43 use std::sync::atomic::AtomicUsize;
44 use std::sync::atomic::Ordering::SeqCst;
47 use termcolor::{ColorSpec, Color};
50 mod diagnostic_builder;
57 use syntax_pos::{BytePos, Loc, FileLinesResult, FileMap, FileName, MultiSpan, Span, NO_EXPANSION};
59 #[derive(Copy, Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
60 pub enum Applicability {
67 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
68 pub struct CodeSuggestion {
69 /// Each substitute can have multiple variants due to multiple
70 /// applicable suggestions
72 /// `foo.bar` might be replaced with `a.b` or `x.y` by replacing
73 /// `foo` and `bar` on their own:
77 /// Substitution { parts: vec![(0..3, "a"), (4..7, "b")] },
78 /// Substitution { parts: vec![(0..3, "x"), (4..7, "y")] },
82 /// or by replacing the entire span:
86 /// Substitution { parts: vec![(0..7, "a.b")] },
87 /// Substitution { parts: vec![(0..7, "x.y")] },
90 pub substitutions: Vec<Substitution>,
92 pub show_code_when_inline: bool,
93 /// Whether or not the suggestion is approximate
95 /// Sometimes we may show suggestions with placeholders,
96 /// which are useful for users but not useful for
97 /// tools like rustfix
98 pub applicability: Applicability,
101 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
102 /// See the docs on `CodeSuggestion::substitutions`
103 pub struct Substitution {
104 pub parts: Vec<SubstitutionPart>,
107 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
108 pub struct SubstitutionPart {
113 pub type CodeMapperDyn = CodeMapper + sync::Send + sync::Sync;
115 pub trait CodeMapper {
116 fn lookup_char_pos(&self, pos: BytePos) -> Loc;
117 fn span_to_lines(&self, sp: Span) -> FileLinesResult;
118 fn span_to_string(&self, sp: Span) -> String;
119 fn span_to_filename(&self, sp: Span) -> FileName;
120 fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
121 fn call_span_if_macro(&self, sp: Span) -> Span;
122 fn ensure_filemap_source_present(&self, file_map: Lrc<FileMap>) -> bool;
123 fn doctest_offset_line(&self, line: usize) -> usize;
126 impl CodeSuggestion {
127 /// Returns the assembled code suggestions and whether they should be shown with an underline.
128 pub fn splice_lines(&self, cm: &CodeMapperDyn)
129 -> Vec<(String, Vec<SubstitutionPart>)> {
130 use syntax_pos::{CharPos, Loc, Pos};
132 fn push_trailing(buf: &mut String,
133 line_opt: Option<&Cow<str>>,
135 hi_opt: Option<&Loc>) {
136 let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
137 if let Some(line) = line_opt {
138 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
139 let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
140 buf.push_str(match hi_opt {
141 Some(hi) => &line[lo..hi],
145 if let None = hi_opt {
151 assert!(!self.substitutions.is_empty());
153 self.substitutions.iter().cloned().map(|mut substitution| {
154 // Assumption: all spans are in the same file, and all spans
155 // are disjoint. Sort in ascending order.
156 substitution.parts.sort_by_key(|part| part.span.lo());
158 // Find the bounding span.
159 let lo = substitution.parts.iter().map(|part| part.span.lo()).min().unwrap();
160 let hi = substitution.parts.iter().map(|part| part.span.hi()).min().unwrap();
161 let bounding_span = Span::new(lo, hi, NO_EXPANSION);
162 let lines = cm.span_to_lines(bounding_span).unwrap();
163 assert!(!lines.lines.is_empty());
165 // To build up the result, we do this for each span:
166 // - push the line segment trailing the previous span
167 // (at the beginning a "phantom" span pointing at the start of the line)
168 // - push lines between the previous and current span (if any)
169 // - if the previous and current span are not on the same line
170 // push the line segment leading up to the current span
171 // - splice in the span substitution
173 // Finally push the trailing line segment of the last span
174 let fm = &lines.file;
175 let mut prev_hi = cm.lookup_char_pos(bounding_span.lo());
176 prev_hi.col = CharPos::from_usize(0);
178 let mut prev_line = fm.get_line(lines.lines[0].line_index);
179 let mut buf = String::new();
181 for part in &substitution.parts {
182 let cur_lo = cm.lookup_char_pos(part.span.lo());
183 if prev_hi.line == cur_lo.line {
184 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
186 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
187 // push lines between the previous and current span (if any)
188 for idx in prev_hi.line..(cur_lo.line - 1) {
189 if let Some(line) = fm.get_line(idx) {
190 buf.push_str(line.as_ref());
194 if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
195 buf.push_str(&cur_line[..cur_lo.col.to_usize()]);
198 buf.push_str(&part.snippet);
199 prev_hi = cm.lookup_char_pos(part.span.hi());
200 prev_line = fm.get_line(prev_hi.line - 1);
202 // if the replacement already ends with a newline, don't print the next line
203 if !buf.ends_with('\n') {
204 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
206 // remove trailing newlines
207 while buf.ends_with('\n') {
210 (buf, substitution.parts)
215 /// Used as a return value to signify a fatal error occurred. (It is also
216 /// used as the argument to panic at the moment, but that will eventually
218 #[derive(Copy, Clone, Debug)]
220 pub struct FatalError;
222 pub struct FatalErrorMarker;
224 // Don't implement Send on FatalError. This makes it impossible to panic!(FatalError).
225 // We don't want to invoke the panic handler and print a backtrace for fatal errors.
226 impl !Send for FatalError {}
229 pub fn raise(self) -> ! {
230 panic::resume_unwind(Box::new(FatalErrorMarker))
234 impl fmt::Display for FatalError {
235 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236 write!(f, "parser fatal error")
240 impl error::Error for FatalError {
241 fn description(&self) -> &str {
242 "The parser has encountered a fatal error"
246 /// Signifies that the compiler died with an explicit call to `.bug`
247 /// or `.span_bug` rather than a failed assertion, etc.
248 #[derive(Copy, Clone, Debug)]
249 pub struct ExplicitBug;
251 impl fmt::Display for ExplicitBug {
252 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
253 write!(f, "parser internal bug")
257 impl error::Error for ExplicitBug {
258 fn description(&self) -> &str {
259 "The parser has encountered an internal bug"
263 pub use diagnostic::{Diagnostic, SubDiagnostic, DiagnosticStyledString, DiagnosticId};
264 pub use diagnostic_builder::DiagnosticBuilder;
266 /// A handler deals with errors; certain errors
267 /// (fatal, bug, unimpl) may cause immediate exit,
268 /// others log errors for later reporting.
270 pub flags: HandlerFlags,
272 err_count: AtomicUsize,
273 emitter: Lock<Box<Emitter + sync::Send>>,
274 continue_after_error: LockCell<bool>,
275 delayed_span_bug: Lock<Option<Diagnostic>>,
277 // This set contains the `DiagnosticId` of all emitted diagnostics to avoid
278 // emitting the same diagnostic with extended help (`--teach`) twice, which
279 // would be uneccessary repetition.
280 taught_diagnostics: Lock<FxHashSet<DiagnosticId>>,
282 /// Used to suggest rustc --explain <error code>
283 emitted_diagnostic_codes: Lock<FxHashSet<DiagnosticId>>,
285 // This set contains a hash of every diagnostic that has been emitted by
286 // this handler. These hashes is used to avoid emitting the same error
288 emitted_diagnostics: Lock<FxHashSet<u128>>,
291 fn default_track_diagnostic(_: &Diagnostic) {}
293 thread_local!(pub static TRACK_DIAGNOSTICS: Cell<fn(&Diagnostic)> =
294 Cell::new(default_track_diagnostic));
297 pub struct HandlerFlags {
298 pub can_emit_warnings: bool,
299 pub treat_err_as_bug: bool,
300 pub external_macro_backtrace: bool,
304 pub fn with_tty_emitter(color_config: ColorConfig,
305 can_emit_warnings: bool,
306 treat_err_as_bug: bool,
307 cm: Option<Lrc<CodeMapperDyn>>)
309 Handler::with_tty_emitter_and_flags(
315 .. Default::default()
319 pub fn with_tty_emitter_and_flags(color_config: ColorConfig,
320 cm: Option<Lrc<CodeMapperDyn>>,
323 let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false));
324 Handler::with_emitter_and_flags(emitter, flags)
327 pub fn with_emitter(can_emit_warnings: bool,
328 treat_err_as_bug: bool,
329 e: Box<Emitter + sync::Send>)
331 Handler::with_emitter_and_flags(
336 .. Default::default()
340 pub fn with_emitter_and_flags(e: Box<Emitter + sync::Send>, flags: HandlerFlags) -> Handler {
343 err_count: AtomicUsize::new(0),
344 emitter: Lock::new(e),
345 continue_after_error: LockCell::new(true),
346 delayed_span_bug: Lock::new(None),
347 taught_diagnostics: Lock::new(FxHashSet()),
348 emitted_diagnostic_codes: Lock::new(FxHashSet()),
349 emitted_diagnostics: Lock::new(FxHashSet()),
353 pub fn set_continue_after_error(&self, continue_after_error: bool) {
354 self.continue_after_error.set(continue_after_error);
357 /// Resets the diagnostic error count as well as the cached emitted diagnostics.
359 /// NOTE: DO NOT call this function from rustc. It is only meant to be called from external
360 /// tools that want to reuse a `Parser` cleaning the previously emitted diagnostics as well as
361 /// the overall count of emitted error diagnostics.
362 pub fn reset_err_count(&self) {
363 *self.emitted_diagnostics.borrow_mut() = FxHashSet();
364 self.err_count.store(0, SeqCst);
367 pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> {
368 DiagnosticBuilder::new(self, Level::Cancelled, "")
371 pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
374 -> DiagnosticBuilder<'a> {
375 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
377 if !self.flags.can_emit_warnings {
382 pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self,
386 -> DiagnosticBuilder<'a> {
387 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
390 if !self.flags.can_emit_warnings {
395 pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
396 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
397 if !self.flags.can_emit_warnings {
402 pub fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
405 -> DiagnosticBuilder<'a> {
406 let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
410 pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
414 -> DiagnosticBuilder<'a> {
415 let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
420 // FIXME: This method should be removed (every error should have an associated error code).
421 pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
422 DiagnosticBuilder::new(self, Level::Error, msg)
424 pub fn struct_err_with_code<'a>(
428 ) -> DiagnosticBuilder<'a> {
429 let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
433 pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
436 -> DiagnosticBuilder<'a> {
437 let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
441 pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self,
445 -> DiagnosticBuilder<'a> {
446 let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
451 pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
452 DiagnosticBuilder::new(self, Level::Fatal, msg)
455 pub fn cancel(&self, err: &mut DiagnosticBuilder) {
459 fn panic_if_treat_err_as_bug(&self) {
460 if self.flags.treat_err_as_bug {
461 panic!("encountered error with `-Z treat_err_as_bug");
465 pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError {
466 self.emit(&sp.into(), msg, Fatal);
469 pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self,
474 self.emit_with_code(&sp.into(), msg, code, Fatal);
477 pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
478 self.emit(&sp.into(), msg, Error);
480 pub fn mut_span_err<'a, S: Into<MultiSpan>>(&'a self,
483 -> DiagnosticBuilder<'a> {
484 let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
488 pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
489 self.emit_with_code(&sp.into(), msg, code, Error);
491 pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
492 self.emit(&sp.into(), msg, Warning);
494 pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
495 self.emit_with_code(&sp.into(), msg, code, Warning);
497 pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
498 self.emit(&sp.into(), msg, Bug);
501 pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
502 if self.flags.treat_err_as_bug {
503 self.span_bug(sp, msg);
505 let mut diagnostic = Diagnostic::new(Level::Bug, msg);
506 diagnostic.set_span(sp.into());
507 *self.delayed_span_bug.borrow_mut() = Some(diagnostic);
509 pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
510 self.emit(&sp.into(), msg, Bug);
512 pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
513 self.emit(&sp.into(), msg, Note);
515 pub fn span_note_diag<'a>(&'a self,
518 -> DiagnosticBuilder<'a> {
519 let mut db = DiagnosticBuilder::new(self, Note, msg);
523 pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
524 self.span_bug(sp, &format!("unimplemented {}", msg));
526 pub fn failure(&self, msg: &str) {
527 DiagnosticBuilder::new(self, FailureNote, msg).emit()
529 pub fn fatal(&self, msg: &str) -> FatalError {
530 if self.flags.treat_err_as_bug {
533 DiagnosticBuilder::new(self, Fatal, msg).emit();
536 pub fn err(&self, msg: &str) {
537 if self.flags.treat_err_as_bug {
540 let mut db = DiagnosticBuilder::new(self, Error, msg);
543 pub fn warn(&self, msg: &str) {
544 let mut db = DiagnosticBuilder::new(self, Warning, msg);
547 pub fn note_without_error(&self, msg: &str) {
548 let mut db = DiagnosticBuilder::new(self, Note, msg);
551 pub fn bug(&self, msg: &str) -> ! {
552 let mut db = DiagnosticBuilder::new(self, Bug, msg);
556 pub fn unimpl(&self, msg: &str) -> ! {
557 self.bug(&format!("unimplemented {}", msg));
560 fn bump_err_count(&self) {
561 self.panic_if_treat_err_as_bug();
562 self.err_count.fetch_add(1, SeqCst);
565 pub fn err_count(&self) -> usize {
566 self.err_count.load(SeqCst)
569 pub fn has_errors(&self) -> bool {
573 pub fn print_error_count(&self) {
574 let s = match self.err_count() {
576 1 => "aborting due to previous error".to_string(),
577 _ => format!("aborting due to {} previous errors", self.err_count())
580 let _ = self.fatal(&s);
582 let can_show_explain = self.emitter.borrow().should_show_explain();
583 let are_there_diagnostics = !self.emitted_diagnostic_codes.borrow().is_empty();
584 if can_show_explain && are_there_diagnostics {
585 let mut error_codes =
586 self.emitted_diagnostic_codes.borrow()
589 .filter_map(|x| match x {
590 DiagnosticId::Error(ref s) => Some(s.clone()),
593 .collect::<Vec<_>>();
594 if !error_codes.is_empty() {
596 if error_codes.len() > 1 {
597 let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
598 self.failure(&format!("Some errors occurred: {}{}",
599 error_codes[..limit].join(", "),
600 if error_codes.len() > 9 { "..." } else { "." }));
601 self.failure(&format!("For more information about an error, try \
602 `rustc --explain {}`.",
605 self.failure(&format!("For more information about this error, try \
606 `rustc --explain {}`.",
613 pub fn abort_if_errors(&self) {
614 if self.err_count() == 0 {
615 if let Some(bug) = self.delayed_span_bug.borrow_mut().take() {
616 DiagnosticBuilder::new_diagnostic(self, bug).emit();
622 pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) {
623 if lvl == Warning && !self.flags.can_emit_warnings {
626 let mut db = DiagnosticBuilder::new(self, lvl, msg);
627 db.set_span(msp.clone());
629 if !self.continue_after_error.get() {
630 self.abort_if_errors();
633 pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: DiagnosticId, lvl: Level) {
634 if lvl == Warning && !self.flags.can_emit_warnings {
637 let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code), msg);
638 db.set_span(msp.clone());
640 if !self.continue_after_error.get() {
641 self.abort_if_errors();
645 /// `true` if we haven't taught a diagnostic with this code already.
646 /// The caller must then teach the user about such a diagnostic.
648 /// Used to suppress emitting the same error multiple times with extended explanation when
649 /// calling `-Zteach`.
650 pub fn must_teach(&self, code: &DiagnosticId) -> bool {
651 self.taught_diagnostics.borrow_mut().insert(code.clone())
654 pub fn force_print_db(&self, mut db: DiagnosticBuilder) {
655 self.emitter.borrow_mut().emit(&db);
659 fn emit_db(&self, db: &DiagnosticBuilder) {
660 let diagnostic = &**db;
662 TRACK_DIAGNOSTICS.with(|track_diagnostics| {
663 track_diagnostics.get()(diagnostic);
666 if let Some(ref code) = diagnostic.code {
667 self.emitted_diagnostic_codes.borrow_mut().insert(code.clone());
670 let diagnostic_hash = {
672 let mut hasher = StableHasher::new();
673 diagnostic.hash(&mut hasher);
677 // Only emit the diagnostic if we haven't already emitted an equivalent
679 if self.emitted_diagnostics.borrow_mut().insert(diagnostic_hash) {
680 self.emitter.borrow_mut().emit(db);
682 self.bump_err_count();
689 #[derive(Copy, PartialEq, Clone, Hash, Debug, RustcEncodable, RustcDecodable)]
693 // An error which while not immediately fatal, should stop the compiler
694 // progressing beyond the current phase.
704 impl fmt::Display for Level {
705 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
711 fn color(self) -> ColorSpec {
712 let mut spec = ColorSpec::new();
714 Bug | Fatal | PhaseFatal | Error => {
715 spec.set_fg(Some(Color::Red))
719 spec.set_fg(Some(Color::Yellow))
720 .set_intense(cfg!(windows));
723 spec.set_fg(Some(Color::Green))
727 spec.set_fg(Some(Color::Cyan))
731 Cancelled => unreachable!(),
736 pub fn to_str(self) -> &'static str {
738 Bug => "error: internal compiler error",
739 Fatal | PhaseFatal | Error => "error",
740 Warning => "warning",
744 Cancelled => panic!("Shouldn't call on cancelled error"),
748 pub fn is_failure_note(&self) -> bool {