]> git.proxmox.com Git - rustc.git/blame - src/librustc_errors/lib.rs
New upstream version 1.17.0+dfsg1
[rustc.git] / src / librustc_errors / lib.rs
CommitLineData
9cc50fc6
SL
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.
4//
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.
10
3157f602
XL
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/")]
32a655c1 18#![deny(warnings)]
3157f602
XL
19
20#![feature(custom_attribute)]
21#![allow(unused_attributes)]
22#![feature(rustc_private)]
23#![feature(staged_api)]
3157f602
XL
24#![feature(range_contains)]
25#![feature(libc)]
3157f602 26
3157f602 27extern crate term;
c30ab7b3 28extern crate libc;
8bb4bdeb 29extern crate serialize as rustc_serialize;
3157f602
XL
30extern crate syntax_pos;
31
32pub use emitter::ColorConfig;
9cc50fc6
SL
33
34use self::Level::*;
9cc50fc6 35
3157f602 36use emitter::{Emitter, EmitterWriter};
9cc50fc6
SL
37
38use std::cell::{RefCell, Cell};
39use std::{error, fmt};
9cc50fc6 40use std::rc::Rc;
9cc50fc6 41
c30ab7b3
SL
42pub mod diagnostic;
43pub mod diagnostic_builder;
9cc50fc6 44pub mod emitter;
a7813a04 45pub mod snippet;
3157f602 46pub mod registry;
5bcae85e 47pub mod styled_buffer;
9e0c209e 48mod lock;
3157f602 49
c30ab7b3
SL
50use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION};
51use syntax_pos::MacroBacktrace;
9cc50fc6 52
8bb4bdeb 53#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
9cc50fc6
SL
54pub enum RenderSpan {
55 /// A FullSpan renders with both with an initial line for the
56 /// message, prefixed by file:linenum, followed by a summary of
57 /// the source code covered by the span.
7453a54e 58 FullSpan(MultiSpan),
9cc50fc6 59
9cc50fc6
SL
60 /// A suggestion renders with both with an initial line for the
61 /// message, prefixed by file:linenum, followed by a summary
7453a54e
SL
62 /// of hypothetical source code, where each `String` is spliced
63 /// into the lines in place of the code covered by each span.
64 Suggestion(CodeSuggestion),
7453a54e
SL
65}
66
8bb4bdeb 67#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
7453a54e 68pub struct CodeSuggestion {
3157f602
XL
69 pub msp: MultiSpan,
70 pub substitutes: Vec<String>,
71}
72
73pub trait CodeMapper {
74 fn lookup_char_pos(&self, pos: BytePos) -> Loc;
75 fn span_to_lines(&self, sp: Span) -> FileLinesResult;
76 fn span_to_string(&self, sp: Span) -> String;
77 fn span_to_filename(&self, sp: Span) -> FileName;
78 fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>;
9e0c209e 79 fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
9cc50fc6
SL
80}
81
7453a54e
SL
82impl CodeSuggestion {
83 /// Returns the assembled code suggestion.
3157f602
XL
84 pub fn splice_lines(&self, cm: &CodeMapper) -> String {
85 use syntax_pos::{CharPos, Loc, Pos};
7453a54e 86
c30ab7b3
SL
87 fn push_trailing(buf: &mut String,
88 line_opt: Option<&str>,
89 lo: &Loc,
90 hi_opt: Option<&Loc>) {
91 let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
7453a54e 92 if let Some(line) = line_opt {
8bb4bdeb
XL
93 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
94 let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
7453a54e
SL
95 buf.push_str(match hi_opt {
96 Some(hi) => &line[lo..hi],
97 None => &line[lo..],
98 });
99 }
100 if let None = hi_opt {
101 buf.push('\n');
102 }
103 }
9cc50fc6 104 }
7453a54e 105
a7813a04
XL
106 let mut primary_spans = self.msp.primary_spans().to_owned();
107
108 assert_eq!(primary_spans.len(), self.substitutes.len());
109 if primary_spans.is_empty() {
110 return format!("");
111 }
112
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);
116
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();
c30ab7b3
SL
120 let bounding_span = Span {
121 lo: lo,
122 hi: hi,
123 expn_id: NO_EXPANSION,
124 };
a7813a04
XL
125 let lines = cm.span_to_lines(bounding_span).unwrap();
126 assert!(!lines.lines.is_empty());
7453a54e
SL
127
128 // To build up the result, we do this for each span:
129 // - push the line segment trailing the previous span
130 // (at the beginning a "phantom" span pointing at the start of the line)
131 // - push lines between the previous and current span (if any)
132 // - if the previous and current span are not on the same line
133 // push the line segment leading up to the current span
134 // - splice in the span substitution
135 //
136 // Finally push the trailing line segment of the last span
137 let fm = &lines.file;
a7813a04 138 let mut prev_hi = cm.lookup_char_pos(bounding_span.lo);
7453a54e
SL
139 prev_hi.col = CharPos::from_usize(0);
140
141 let mut prev_line = fm.get_line(lines.lines[0].line_index);
142 let mut buf = String::new();
143
a7813a04 144 for (sp, substitute) in primary_spans.iter().zip(self.substitutes.iter()) {
7453a54e
SL
145 let cur_lo = cm.lookup_char_pos(sp.lo);
146 if prev_hi.line == cur_lo.line {
147 push_trailing(&mut buf, prev_line, &prev_hi, Some(&cur_lo));
148 } else {
149 push_trailing(&mut buf, prev_line, &prev_hi, None);
150 // push lines between the previous and current span (if any)
151 for idx in prev_hi.line..(cur_lo.line - 1) {
152 if let Some(line) = fm.get_line(idx) {
153 buf.push_str(line);
154 buf.push('\n');
155 }
156 }
157 if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
c30ab7b3 158 buf.push_str(&cur_line[..cur_lo.col.to_usize()]);
7453a54e
SL
159 }
160 }
161 buf.push_str(substitute);
162 prev_hi = cm.lookup_char_pos(sp.hi);
163 prev_line = fm.get_line(prev_hi.line - 1);
164 }
165 push_trailing(&mut buf, prev_line, &prev_hi, None);
166 // remove trailing newline
167 buf.pop();
168 buf
9cc50fc6
SL
169 }
170}
171
172/// Used as a return value to signify a fatal error occurred. (It is also
173/// used as the argument to panic at the moment, but that will eventually
174/// not be true.)
175#[derive(Copy, Clone, Debug)]
176#[must_use]
177pub struct FatalError;
178
179impl fmt::Display for FatalError {
180 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
181 write!(f, "parser fatal error")
182 }
183}
184
185impl error::Error for FatalError {
186 fn description(&self) -> &str {
187 "The parser has encountered a fatal error"
188 }
189}
190
191/// Signifies that the compiler died with an explicit call to `.bug`
192/// or `.span_bug` rather than a failed assertion, etc.
193#[derive(Copy, Clone, Debug)]
194pub struct ExplicitBug;
195
196impl fmt::Display for ExplicitBug {
197 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
198 write!(f, "parser internal bug")
199 }
200}
201
202impl error::Error for ExplicitBug {
203 fn description(&self) -> &str {
204 "The parser has encountered an internal bug"
205 }
206}
207
c30ab7b3
SL
208pub use diagnostic::{Diagnostic, SubDiagnostic};
209pub use diagnostic_builder::DiagnosticBuilder;
9cc50fc6
SL
210
211/// A handler deals with errors; certain errors
212/// (fatal, bug, unimpl) may cause immediate exit,
213/// others log errors for later reporting.
214pub struct Handler {
215 err_count: Cell<usize>,
5bcae85e 216 emitter: RefCell<Box<Emitter>>,
9cc50fc6
SL
217 pub can_emit_warnings: bool,
218 treat_err_as_bug: bool,
7453a54e
SL
219 continue_after_error: Cell<bool>,
220 delayed_span_bug: RefCell<Option<(MultiSpan, String)>>,
9cc50fc6
SL
221}
222
223impl Handler {
224 pub fn with_tty_emitter(color_config: ColorConfig,
9cc50fc6
SL
225 can_emit_warnings: bool,
226 treat_err_as_bug: bool,
5bcae85e 227 cm: Option<Rc<CodeMapper>>)
9cc50fc6 228 -> Handler {
5bcae85e 229 let emitter = Box::new(EmitterWriter::stderr(color_config, cm));
9cc50fc6
SL
230 Handler::with_emitter(can_emit_warnings, treat_err_as_bug, emitter)
231 }
232
233 pub fn with_emitter(can_emit_warnings: bool,
234 treat_err_as_bug: bool,
c30ab7b3
SL
235 e: Box<Emitter>)
236 -> Handler {
9cc50fc6
SL
237 Handler {
238 err_count: Cell::new(0),
5bcae85e 239 emitter: RefCell::new(e),
9cc50fc6
SL
240 can_emit_warnings: can_emit_warnings,
241 treat_err_as_bug: treat_err_as_bug,
7453a54e 242 continue_after_error: Cell::new(true),
9cc50fc6
SL
243 delayed_span_bug: RefCell::new(None),
244 }
245 }
246
7453a54e
SL
247 pub fn set_continue_after_error(&self, continue_after_error: bool) {
248 self.continue_after_error.set(continue_after_error);
249 }
250
9cc50fc6 251 pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> {
a7813a04 252 DiagnosticBuilder::new(self, Level::Cancelled, "")
9cc50fc6
SL
253 }
254
7453a54e
SL
255 pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
256 sp: S,
257 msg: &str)
258 -> DiagnosticBuilder<'a> {
a7813a04
XL
259 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
260 result.set_span(sp);
9cc50fc6
SL
261 if !self.can_emit_warnings {
262 result.cancel();
263 }
264 result
265 }
7453a54e
SL
266 pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self,
267 sp: S,
268 msg: &str,
269 code: &str)
270 -> DiagnosticBuilder<'a> {
a7813a04
XL
271 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
272 result.set_span(sp);
9cc50fc6
SL
273 result.code(code.to_owned());
274 if !self.can_emit_warnings {
275 result.cancel();
276 }
277 result
278 }
279 pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
a7813a04 280 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
9cc50fc6
SL
281 if !self.can_emit_warnings {
282 result.cancel();
283 }
284 result
285 }
7453a54e
SL
286 pub fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
287 sp: S,
288 msg: &str)
289 -> DiagnosticBuilder<'a> {
a7813a04
XL
290 let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
291 result.set_span(sp);
9cc50fc6
SL
292 result
293 }
7453a54e
SL
294 pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
295 sp: S,
296 msg: &str,
297 code: &str)
298 -> DiagnosticBuilder<'a> {
a7813a04
XL
299 let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
300 result.set_span(sp);
9cc50fc6
SL
301 result.code(code.to_owned());
302 result
303 }
304 pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
a7813a04 305 DiagnosticBuilder::new(self, Level::Error, msg)
9cc50fc6 306 }
7453a54e
SL
307 pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
308 sp: S,
309 msg: &str)
310 -> DiagnosticBuilder<'a> {
a7813a04
XL
311 let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
312 result.set_span(sp);
9cc50fc6
SL
313 result
314 }
7453a54e
SL
315 pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self,
316 sp: S,
317 msg: &str,
318 code: &str)
319 -> DiagnosticBuilder<'a> {
a7813a04
XL
320 let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
321 result.set_span(sp);
9cc50fc6
SL
322 result.code(code.to_owned());
323 result
324 }
325 pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
a7813a04 326 DiagnosticBuilder::new(self, Level::Fatal, msg)
9cc50fc6
SL
327 }
328
5bcae85e 329 pub fn cancel(&self, err: &mut DiagnosticBuilder) {
9cc50fc6
SL
330 err.cancel();
331 }
332
a7813a04 333 fn panic_if_treat_err_as_bug(&self) {
9cc50fc6 334 if self.treat_err_as_bug {
a7813a04 335 panic!("encountered error with `-Z treat_err_as_bug");
9cc50fc6 336 }
a7813a04
XL
337 }
338
c30ab7b3 339 pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError {
a7813a04 340 self.emit(&sp.into(), msg, Fatal);
a7813a04 341 self.panic_if_treat_err_as_bug();
9cc50fc6
SL
342 return FatalError;
343 }
c30ab7b3
SL
344 pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self,
345 sp: S,
346 msg: &str,
347 code: &str)
a7813a04
XL
348 -> FatalError {
349 self.emit_with_code(&sp.into(), msg, code, Fatal);
a7813a04 350 self.panic_if_treat_err_as_bug();
9cc50fc6
SL
351 return FatalError;
352 }
7453a54e 353 pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
a7813a04 354 self.emit(&sp.into(), msg, Error);
a7813a04 355 self.panic_if_treat_err_as_bug();
9cc50fc6 356 }
9e0c209e
SL
357 pub fn mut_span_err<'a, S: Into<MultiSpan>>(&'a self,
358 sp: S,
359 msg: &str)
360 -> DiagnosticBuilder<'a> {
361 let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
362 result.set_span(sp);
9e0c209e
SL
363 result
364 }
7453a54e 365 pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
a7813a04 366 self.emit_with_code(&sp.into(), msg, code, Error);
a7813a04 367 self.panic_if_treat_err_as_bug();
9cc50fc6 368 }
7453a54e 369 pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
a7813a04 370 self.emit(&sp.into(), msg, Warning);
9cc50fc6 371 }
7453a54e 372 pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
a7813a04 373 self.emit_with_code(&sp.into(), msg, code, Warning);
9cc50fc6 374 }
7453a54e 375 pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
a7813a04 376 self.emit(&sp.into(), msg, Bug);
9cc50fc6
SL
377 panic!(ExplicitBug);
378 }
7453a54e 379 pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
9cc50fc6 380 let mut delayed = self.delayed_span_bug.borrow_mut();
7453a54e 381 *delayed = Some((sp.into(), msg.to_string()));
9cc50fc6 382 }
7453a54e 383 pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
a7813a04 384 self.emit(&sp.into(), msg, Bug);
9cc50fc6 385 }
7453a54e 386 pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
5bcae85e 387 self.emit(&sp.into(), msg, Note);
9cc50fc6 388 }
7453a54e 389 pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
9cc50fc6
SL
390 self.span_bug(sp, &format!("unimplemented {}", msg));
391 }
392 pub fn fatal(&self, msg: &str) -> FatalError {
393 if self.treat_err_as_bug {
394 self.bug(msg);
395 }
c30ab7b3 396 let mut db = DiagnosticBuilder::new(self, Fatal, msg);
5bcae85e 397 db.emit();
9cc50fc6
SL
398 FatalError
399 }
400 pub fn err(&self, msg: &str) {
401 if self.treat_err_as_bug {
402 self.bug(msg);
403 }
c30ab7b3 404 let mut db = DiagnosticBuilder::new(self, Error, msg);
5bcae85e 405 db.emit();
9cc50fc6
SL
406 }
407 pub fn warn(&self, msg: &str) {
c30ab7b3 408 let mut db = DiagnosticBuilder::new(self, Warning, msg);
5bcae85e 409 db.emit();
9cc50fc6
SL
410 }
411 pub fn note_without_error(&self, msg: &str) {
c30ab7b3 412 let mut db = DiagnosticBuilder::new(self, Note, msg);
5bcae85e 413 db.emit();
9cc50fc6
SL
414 }
415 pub fn bug(&self, msg: &str) -> ! {
c30ab7b3 416 let mut db = DiagnosticBuilder::new(self, Bug, msg);
5bcae85e 417 db.emit();
9cc50fc6
SL
418 panic!(ExplicitBug);
419 }
420 pub fn unimpl(&self, msg: &str) -> ! {
421 self.bug(&format!("unimplemented {}", msg));
422 }
423
424 pub fn bump_err_count(&self) {
425 self.err_count.set(self.err_count.get() + 1);
426 }
427
428 pub fn err_count(&self) -> usize {
429 self.err_count.get()
430 }
431
432 pub fn has_errors(&self) -> bool {
433 self.err_count.get() > 0
434 }
9cc50fc6
SL
435 pub fn abort_if_errors(&self) {
436 let s;
437 match self.err_count.get() {
438 0 => {
439 let delayed_bug = self.delayed_span_bug.borrow();
440 match *delayed_bug {
7453a54e
SL
441 Some((ref span, ref errmsg)) => {
442 self.span_bug(span.clone(), errmsg);
c30ab7b3 443 }
9cc50fc6
SL
444 _ => {}
445 }
446
447 return;
448 }
449 1 => s = "aborting due to previous error".to_string(),
c30ab7b3
SL
450 _ => {
451 s = format!("aborting due to {} previous errors", self.err_count.get());
9cc50fc6
SL
452 }
453 }
454
455 panic!(self.fatal(&s));
456 }
c30ab7b3
SL
457 pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) {
458 if lvl == Warning && !self.can_emit_warnings {
459 return;
460 }
5bcae85e
SL
461 let mut db = DiagnosticBuilder::new(self, lvl, msg);
462 db.set_span(msp.clone());
463 db.emit();
c30ab7b3
SL
464 if !self.continue_after_error.get() {
465 self.abort_if_errors();
466 }
467 }
468 pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: &str, lvl: Level) {
469 if lvl == Warning && !self.can_emit_warnings {
470 return;
471 }
472 let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code.to_owned()), msg);
5bcae85e
SL
473 db.set_span(msp.clone());
474 db.emit();
c30ab7b3
SL
475 if !self.continue_after_error.get() {
476 self.abort_if_errors();
477 }
9cc50fc6
SL
478 }
479}
480
481
8bb4bdeb 482#[derive(Copy, PartialEq, Clone, Debug, RustcEncodable, RustcDecodable)]
9cc50fc6
SL
483pub enum Level {
484 Bug,
485 Fatal,
7453a54e
SL
486 // An error which while not immediately fatal, should stop the compiler
487 // progressing beyond the current phase.
488 PhaseFatal,
9cc50fc6
SL
489 Error,
490 Warning,
491 Note,
492 Help,
493 Cancelled,
494}
495
496impl fmt::Display for Level {
497 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
9cc50fc6
SL
498 self.to_str().fmt(f)
499 }
500}
501
502impl Level {
3157f602 503 pub fn color(self) -> term::color::Color {
9cc50fc6 504 match self {
7453a54e 505 Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED,
9e0c209e
SL
506 Warning => {
507 if cfg!(windows) {
508 term::color::BRIGHT_YELLOW
509 } else {
510 term::color::YELLOW
511 }
c30ab7b3 512 }
9cc50fc6
SL
513 Note => term::color::BRIGHT_GREEN,
514 Help => term::color::BRIGHT_CYAN,
515 Cancelled => unreachable!(),
516 }
517 }
518
3157f602 519 pub fn to_str(self) -> &'static str {
9cc50fc6
SL
520 match self {
521 Bug => "error: internal compiler error",
7453a54e 522 Fatal | PhaseFatal | Error => "error",
9cc50fc6
SL
523 Warning => "warning",
524 Note => "note",
525 Help => "help",
526 Cancelled => panic!("Shouldn't call on cancelled error"),
527 }
528 }
529}
530
c30ab7b3
SL
531pub fn expect<T, M>(diag: &Handler, opt: Option<T>, msg: M) -> T
532 where M: FnOnce() -> String
9cc50fc6
SL
533{
534 match opt {
535 Some(t) => t,
536 None => diag.bug(&msg()),
537 }
9e0c209e 538}