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 #![crate_name = "rustc_errors"]
12 #![unstable(feature = "rustc_private", issue = "27812")]
13 #![crate_type = "dylib"]
14 #![crate_type = "rlib"]
15 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
16 html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
17 html_root_url = "https://doc.rust-lang.org/nightly/")]
18 #![cfg_attr(not(stage0), deny(warnings))]
20 #![feature(custom_attribute)]
21 #![allow(unused_attributes)]
22 #![feature(rustc_private)]
23 #![feature(staged_api)]
24 #![feature(question_mark)]
25 #![feature(range_contains)]
29 extern crate serialize;
31 #[macro_use] extern crate log;
32 #[macro_use] extern crate libc;
33 extern crate rustc_unicode;
34 extern crate serialize as rustc_serialize; // used by deriving
35 extern crate syntax_pos;
37 pub use emitter::ColorConfig;
40 use self::RenderSpan::*;
42 use emitter::{Emitter, EmitterWriter};
44 use std::cell::{RefCell, Cell};
45 use std::{error, fmt};
47 use std::thread::panicking;
52 pub mod styled_buffer;
54 use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION };
55 use syntax_pos::{MacroBacktrace};
59 /// A FullSpan renders with both with an initial line for the
60 /// message, prefixed by file:linenum, followed by a summary of
61 /// the source code covered by the span.
64 /// A suggestion renders with both with an initial line for the
65 /// message, prefixed by file:linenum, followed by a summary
66 /// of hypothetical source code, where each `String` is spliced
67 /// into the lines in place of the code covered by each span.
68 Suggestion(CodeSuggestion),
72 pub struct CodeSuggestion {
74 pub substitutes: Vec<String>,
77 pub trait CodeMapper {
78 fn lookup_char_pos(&self, pos: BytePos) -> Loc;
79 fn span_to_lines(&self, sp: Span) -> FileLinesResult;
80 fn span_to_string(&self, sp: Span) -> String;
81 fn span_to_filename(&self, sp: Span) -> FileName;
82 fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>;
86 /// Returns the assembled code suggestion.
87 pub fn splice_lines(&self, cm: &CodeMapper) -> String {
88 use syntax_pos::{CharPos, Loc, Pos};
90 fn push_trailing(buf: &mut String, line_opt: Option<&str>,
91 lo: &Loc, hi_opt: Option<&Loc>) {
92 let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi|hi.col.to_usize()));
93 if let Some(line) = line_opt {
95 buf.push_str(match hi_opt {
96 Some(hi) => &line[lo..hi],
100 if let None = hi_opt {
106 let mut primary_spans = self.msp.primary_spans().to_owned();
108 assert_eq!(primary_spans.len(), self.substitutes.len());
109 if primary_spans.is_empty() {
113 // Assumption: all spans are in the same file, and all spans
114 // are disjoint. Sort in ascending order.
115 primary_spans.sort_by_key(|sp| sp.lo);
117 // Find the bounding span.
118 let lo = primary_spans.iter().map(|sp| sp.lo).min().unwrap();
119 let hi = primary_spans.iter().map(|sp| sp.hi).min().unwrap();
120 let bounding_span = Span { lo: lo, hi: hi, expn_id: NO_EXPANSION };
121 let lines = cm.span_to_lines(bounding_span).unwrap();
122 assert!(!lines.lines.is_empty());
124 // To build up the result, we do this for each span:
125 // - push the line segment trailing the previous span
126 // (at the beginning a "phantom" span pointing at the start of the line)
127 // - push lines between the previous and current span (if any)
128 // - if the previous and current span are not on the same line
129 // push the line segment leading up to the current span
130 // - splice in the span substitution
132 // Finally push the trailing line segment of the last span
133 let fm = &lines.file;
134 let mut prev_hi = cm.lookup_char_pos(bounding_span.lo);
135 prev_hi.col = CharPos::from_usize(0);
137 let mut prev_line = fm.get_line(lines.lines[0].line_index);
138 let mut buf = String::new();
140 for (sp, substitute) in primary_spans.iter().zip(self.substitutes.iter()) {
141 let cur_lo = cm.lookup_char_pos(sp.lo);
142 if prev_hi.line == cur_lo.line {
143 push_trailing(&mut buf, prev_line, &prev_hi, Some(&cur_lo));
145 push_trailing(&mut buf, prev_line, &prev_hi, None);
146 // push lines between the previous and current span (if any)
147 for idx in prev_hi.line..(cur_lo.line - 1) {
148 if let Some(line) = fm.get_line(idx) {
153 if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
154 buf.push_str(&cur_line[.. cur_lo.col.to_usize()]);
157 buf.push_str(substitute);
158 prev_hi = cm.lookup_char_pos(sp.hi);
159 prev_line = fm.get_line(prev_hi.line - 1);
161 push_trailing(&mut buf, prev_line, &prev_hi, None);
162 // remove trailing newline
168 /// Used as a return value to signify a fatal error occurred. (It is also
169 /// used as the argument to panic at the moment, but that will eventually
171 #[derive(Copy, Clone, Debug)]
173 pub struct FatalError;
175 impl fmt::Display for FatalError {
176 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
177 write!(f, "parser fatal error")
181 impl error::Error for FatalError {
182 fn description(&self) -> &str {
183 "The parser has encountered a fatal error"
187 /// Signifies that the compiler died with an explicit call to `.bug`
188 /// or `.span_bug` rather than a failed assertion, etc.
189 #[derive(Copy, Clone, Debug)]
190 pub struct ExplicitBug;
192 impl fmt::Display for ExplicitBug {
193 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
194 write!(f, "parser internal bug")
198 impl error::Error for ExplicitBug {
199 fn description(&self) -> &str {
200 "The parser has encountered an internal bug"
204 /// Used for emitting structured error messages and other diagnostic information.
207 pub struct DiagnosticBuilder<'a> {
208 handler: &'a Handler,
211 pub code: Option<String>,
213 pub children: Vec<SubDiagnostic>,
216 /// For example a note attached to an error.
218 pub struct SubDiagnostic {
222 pub render_span: Option<RenderSpan>,
225 impl<'a> DiagnosticBuilder<'a> {
226 /// Emit the diagnostic.
227 pub fn emit(&mut self) {
228 if self.cancelled() {
232 self.handler.emitter.borrow_mut().emit(&self);
234 self.handler.panic_if_treat_err_as_bug();
236 // if self.is_fatal() {
237 // panic!(FatalError);
241 /// Cancel the diagnostic (a structured diagnostic must either be emitted or
242 /// cancelled or it will panic when dropped).
243 /// BEWARE: if this DiagnosticBuilder is an error, then creating it will
244 /// bump the error count on the Handler and cancelling it won't undo that.
245 /// If you want to decrement the error count you should use `Handler::cancel`.
246 pub fn cancel(&mut self) {
247 self.level = Level::Cancelled;
250 pub fn cancelled(&self) -> bool {
251 self.level == Level::Cancelled
254 pub fn is_fatal(&self) -> bool {
255 self.level == Level::Fatal
258 /// Add a span/label to be included in the resulting snippet.
259 /// This is pushed onto the `MultiSpan` that was created when the
260 /// diagnostic was first built. If you don't call this function at
261 /// all, and you just supplied a `Span` to create the diagnostic,
262 /// then the snippet will just include that `Span`, which is
263 /// called the primary span.
264 pub fn span_label(&mut self, span: Span, label: &fmt::Display)
265 -> &mut DiagnosticBuilder<'a> {
266 self.span.push_span_label(span, format!("{}", label));
270 pub fn note_expected_found(&mut self,
271 label: &fmt::Display,
272 expected: &fmt::Display,
273 found: &fmt::Display)
274 -> &mut DiagnosticBuilder<'a>
276 // For now, just attach these as notes
277 self.note(&format!("expected {} `{}`", label, expected));
278 self.note(&format!(" found {} `{}`", label, found));
282 pub fn note(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> {
283 self.sub(Level::Note, msg, MultiSpan::new(), None);
286 pub fn span_note<S: Into<MultiSpan>>(&mut self,
289 -> &mut DiagnosticBuilder<'a> {
290 self.sub(Level::Note, msg, sp.into(), None);
293 pub fn warn(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> {
294 self.sub(Level::Warning, msg, MultiSpan::new(), None);
297 pub fn span_warn<S: Into<MultiSpan>>(&mut self,
300 -> &mut DiagnosticBuilder<'a> {
301 self.sub(Level::Warning, msg, sp.into(), None);
304 pub fn help(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> {
305 self.sub(Level::Help, msg, MultiSpan::new(), None);
308 pub fn span_help<S: Into<MultiSpan>>(&mut self,
311 -> &mut DiagnosticBuilder<'a> {
312 self.sub(Level::Help, msg, sp.into(), None);
315 /// Prints out a message with a suggested edit of the code.
317 /// See `diagnostic::RenderSpan::Suggestion` for more information.
318 pub fn span_suggestion<S: Into<MultiSpan>>(&mut self,
322 -> &mut DiagnosticBuilder<'a> {
323 self.sub(Level::Help, msg, MultiSpan::new(), Some(Suggestion(CodeSuggestion {
325 substitutes: vec![suggestion],
330 pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
331 self.span = sp.into();
335 pub fn code(&mut self, s: String) -> &mut Self {
340 pub fn message(&self) -> &str {
344 pub fn level(&self) -> Level {
348 /// Convenience function for internal use, clients should use one of the
349 /// struct_* methods on Handler.
350 fn new(handler: &'a Handler,
352 message: &str) -> DiagnosticBuilder<'a> {
353 DiagnosticBuilder::new_with_code(handler, level, None, message)
356 /// Convenience function for internal use, clients should use one of the
357 /// struct_* methods on Handler.
358 fn new_with_code(handler: &'a Handler,
360 code: Option<String>,
361 message: &str) -> DiagnosticBuilder<'a> {
365 message: message.to_owned(),
367 span: MultiSpan::new(),
372 /// Convenience function for internal use, clients should use one of the
373 /// public methods above.
378 render_span: Option<RenderSpan>) {
379 let sub = SubDiagnostic {
381 message: message.to_owned(),
383 render_span: render_span,
385 self.children.push(sub);
389 impl<'a> fmt::Debug for DiagnosticBuilder<'a> {
390 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
395 /// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or
397 impl<'a> Drop for DiagnosticBuilder<'a> {
399 if !panicking() && !self.cancelled() {
400 let mut db = DiagnosticBuilder::new(self.handler,
402 "Error constructed but not emitted");
409 /// A handler deals with errors; certain errors
410 /// (fatal, bug, unimpl) may cause immediate exit,
411 /// others log errors for later reporting.
413 err_count: Cell<usize>,
414 emitter: RefCell<Box<Emitter>>,
415 pub can_emit_warnings: bool,
416 treat_err_as_bug: bool,
417 continue_after_error: Cell<bool>,
418 delayed_span_bug: RefCell<Option<(MultiSpan, String)>>,
422 pub fn with_tty_emitter(color_config: ColorConfig,
423 registry: Option<registry::Registry>,
424 can_emit_warnings: bool,
425 treat_err_as_bug: bool,
426 cm: Option<Rc<CodeMapper>>)
428 let emitter = Box::new(EmitterWriter::stderr(color_config, registry, cm,
429 snippet::FormatMode::EnvironmentSelected));
430 Handler::with_emitter(can_emit_warnings, treat_err_as_bug, emitter)
433 pub fn with_emitter(can_emit_warnings: bool,
434 treat_err_as_bug: bool,
435 e: Box<Emitter>) -> Handler {
437 err_count: Cell::new(0),
438 emitter: RefCell::new(e),
439 can_emit_warnings: can_emit_warnings,
440 treat_err_as_bug: treat_err_as_bug,
441 continue_after_error: Cell::new(true),
442 delayed_span_bug: RefCell::new(None),
446 pub fn set_continue_after_error(&self, continue_after_error: bool) {
447 self.continue_after_error.set(continue_after_error);
450 pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> {
451 DiagnosticBuilder::new(self, Level::Cancelled, "")
454 pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
457 -> DiagnosticBuilder<'a> {
458 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
460 if !self.can_emit_warnings {
465 pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self,
469 -> DiagnosticBuilder<'a> {
470 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
472 result.code(code.to_owned());
473 if !self.can_emit_warnings {
478 pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
479 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
480 if !self.can_emit_warnings {
485 pub fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
488 -> DiagnosticBuilder<'a> {
489 self.bump_err_count();
490 let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
494 pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
498 -> DiagnosticBuilder<'a> {
499 self.bump_err_count();
500 let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
502 result.code(code.to_owned());
505 pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
506 self.bump_err_count();
507 DiagnosticBuilder::new(self, Level::Error, msg)
509 pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
512 -> DiagnosticBuilder<'a> {
513 self.bump_err_count();
514 let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
518 pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self,
522 -> DiagnosticBuilder<'a> {
523 self.bump_err_count();
524 let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
526 result.code(code.to_owned());
529 pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
530 self.bump_err_count();
531 DiagnosticBuilder::new(self, Level::Fatal, msg)
534 pub fn cancel(&mut self, err: &mut DiagnosticBuilder) {
535 if err.level == Level::Error || err.level == Level::Fatal {
536 assert!(self.has_errors());
537 self.err_count.set(self.err_count.get() + 1);
542 fn panic_if_treat_err_as_bug(&self) {
543 if self.treat_err_as_bug {
544 panic!("encountered error with `-Z treat_err_as_bug");
548 pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str)
550 self.emit(&sp.into(), msg, Fatal);
551 self.bump_err_count();
552 self.panic_if_treat_err_as_bug();
555 pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str)
557 self.emit_with_code(&sp.into(), msg, code, Fatal);
558 self.bump_err_count();
559 self.panic_if_treat_err_as_bug();
562 pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
563 self.emit(&sp.into(), msg, Error);
564 self.bump_err_count();
565 self.panic_if_treat_err_as_bug();
567 pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
568 self.emit_with_code(&sp.into(), msg, code, Error);
569 self.bump_err_count();
570 self.panic_if_treat_err_as_bug();
572 pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
573 self.emit(&sp.into(), msg, Warning);
575 pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
576 self.emit_with_code(&sp.into(), msg, code, Warning);
578 pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
579 self.emit(&sp.into(), msg, Bug);
582 pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
583 let mut delayed = self.delayed_span_bug.borrow_mut();
584 *delayed = Some((sp.into(), msg.to_string()));
586 pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
587 self.emit(&sp.into(), msg, Bug);
588 self.bump_err_count();
590 pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
591 self.emit(&sp.into(), msg, Note);
593 pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
594 self.span_bug(sp, &format!("unimplemented {}", msg));
596 pub fn fatal(&self, msg: &str) -> FatalError {
597 if self.treat_err_as_bug {
600 let mut db = DiagnosticBuilder::new(self,
604 self.bump_err_count();
607 pub fn err(&self, msg: &str) {
608 if self.treat_err_as_bug {
611 let mut db = DiagnosticBuilder::new(self,
615 self.bump_err_count();
617 pub fn warn(&self, msg: &str) {
618 let mut db = DiagnosticBuilder::new(self,
623 pub fn note_without_error(&self, msg: &str) {
624 let mut db = DiagnosticBuilder::new(self,
629 pub fn bug(&self, msg: &str) -> ! {
630 let mut db = DiagnosticBuilder::new(self,
636 pub fn unimpl(&self, msg: &str) -> ! {
637 self.bug(&format!("unimplemented {}", msg));
640 pub fn bump_err_count(&self) {
641 self.err_count.set(self.err_count.get() + 1);
644 pub fn err_count(&self) -> usize {
648 pub fn has_errors(&self) -> bool {
649 self.err_count.get() > 0
651 pub fn abort_if_errors(&self) {
653 match self.err_count.get() {
655 let delayed_bug = self.delayed_span_bug.borrow();
657 Some((ref span, ref errmsg)) => {
658 self.span_bug(span.clone(), errmsg);
665 1 => s = "aborting due to previous error".to_string(),
667 s = format!("aborting due to {} previous errors",
668 self.err_count.get());
672 panic!(self.fatal(&s));
678 if lvl == Warning && !self.can_emit_warnings { return }
679 let mut db = DiagnosticBuilder::new(self, lvl, msg);
680 db.set_span(msp.clone());
682 if !self.continue_after_error.get() { self.abort_if_errors(); }
684 pub fn emit_with_code(&self,
689 if lvl == Warning && !self.can_emit_warnings { return }
690 let mut db = DiagnosticBuilder::new_with_code(self,
692 Some(code.to_owned()),
694 db.set_span(msp.clone());
696 if !self.continue_after_error.get() { self.abort_if_errors(); }
701 #[derive(Copy, PartialEq, Clone, Debug)]
705 // An error which while not immediately fatal, should stop the compiler
706 // progressing beyond the current phase.
715 impl fmt::Display for Level {
716 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
722 pub fn color(self) -> term::color::Color {
724 Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED,
725 Warning => term::color::YELLOW,
726 Note => term::color::BRIGHT_GREEN,
727 Help => term::color::BRIGHT_CYAN,
728 Cancelled => unreachable!(),
732 pub fn to_str(self) -> &'static str {
734 Bug => "error: internal compiler error",
735 Fatal | PhaseFatal | Error => "error",
736 Warning => "warning",
739 Cancelled => panic!("Shouldn't call on cancelled error"),
744 pub fn expect<T, M>(diag: &Handler, opt: Option<T>, msg: M) -> T where
745 M: FnOnce() -> String,
749 None => diag.bug(&msg()),
753 /// True if we should use the old-skool error format style. This is
754 /// the default setting until the new errors are deemed stable enough
759 pub fn check_old_school() -> bool {
761 env::var("RUST_NEW_ERROR_FORMAT").is_err()
764 /// For unit tests, use the new format.
766 pub fn check_old_school() -> bool {