Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/librustc/driver/driver.rs
Original file line number Diff line number Diff line change
@@ -931,7 +931,7 @@ pub fn build_session(sopts: @session::Options,
-> Session {
let codemap = @codemap::CodeMap::new();
let diagnostic_handler =
diagnostic::mk_handler();
diagnostic::default_handler();
let span_diagnostic_handler =
diagnostic::mk_span_handler(diagnostic_handler, codemap);

@@ -1149,7 +1149,8 @@ pub fn build_output_filenames(input: &Input,
}

pub fn early_error(msg: &str) -> ! {
diagnostic::DefaultEmitter.emit(None, msg, diagnostic::Fatal);
let mut emitter = diagnostic::EmitterWriter::stderr();
emitter.emit(None, msg, diagnostic::Fatal);
fail!(diagnostic::FatalError);
}

7 changes: 3 additions & 4 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
@@ -394,7 +394,8 @@ pub fn monitor(f: proc()) {
Err(value) => {
// Task failed without emitting a fatal diagnostic
if !value.is::<diagnostic::FatalError>() {
diagnostic::DefaultEmitter.emit(
let mut emitter = diagnostic::EmitterWriter::stderr();
emitter.emit(
None,
diagnostic::ice_msg("unexpected failure"),
diagnostic::Error);
@@ -404,9 +405,7 @@ pub fn monitor(f: proc()) {
this is a bug",
];
for note in xs.iter() {
diagnostic::DefaultEmitter.emit(None,
*note,
diagnostic::Note)
emitter.emit(None, *note, diagnostic::Note)
}

println!("{}", r.read_to_str());
2 changes: 1 addition & 1 deletion src/librustdoc/core.rs
Original file line number Diff line number Diff line change
@@ -58,7 +58,7 @@ fn get_ast_and_resolve(cpath: &Path,
};


let diagnostic_handler = syntax::diagnostic::mk_handler();
let diagnostic_handler = syntax::diagnostic::default_handler();
let span_diagnostic_handler =
syntax::diagnostic::mk_span_handler(diagnostic_handler, parsesess.cm);

2 changes: 1 addition & 1 deletion src/librustdoc/html/highlight.rs
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ use t = syntax::parse::token;
/// Highlights some source code, returning the HTML output.
pub fn highlight(src: &str) -> ~str {
let sess = parse::new_parse_sess();
let handler = diagnostic::mk_handler();
let handler = diagnostic::default_handler();
let span_handler = diagnostic::mk_span_handler(handler, sess.cm);
let fm = parse::string_to_filemap(sess, src.to_owned(), ~"<stdin>");
35 changes: 31 additions & 4 deletions src/librustdoc/test.rs
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ use rustc::metadata::creader::Loader;
use getopts;
use syntax::diagnostic;
use syntax::parse;
use syntax::codemap::CodeMap;

use core;
use clean;
@@ -35,7 +36,6 @@ use passes;
use visit_ast::RustdocVisitor;

pub fn run(input: &str, matches: &getopts::Matches) -> int {
let parsesess = parse::new_parse_sess();
let input_path = Path::new(input);
let input = driver::FileInput(input_path.clone());
let libs = matches.opt_strs("L").map(|s| Path::new(s.as_slice()));
@@ -49,9 +49,12 @@ pub fn run(input: &str, matches: &getopts::Matches) -> int {
};


let diagnostic_handler = diagnostic::mk_handler();
let cm = @CodeMap::new();
let diagnostic_handler = diagnostic::default_handler();
let span_diagnostic_handler =
diagnostic::mk_span_handler(diagnostic_handler, parsesess.cm);
diagnostic::mk_span_handler(diagnostic_handler, cm);
let parsesess = parse::new_parse_sess_special_handler(span_diagnostic_handler,
cm);

let sess = driver::build_session_(sessopts,
Some(input_path),
@@ -112,7 +115,30 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool)
.. (*session::basic_options()).clone()
};

let diagnostic_handler = diagnostic::mk_handler();
// Shuffle around a few input and output handles here. We're going to pass
// an explicit handle into rustc to collect output messages, but we also
// want to catch the error message that rustc prints when it fails.
//
// We take our task-local stderr (likely set by the test runner), and move
// it into another task. This helper task then acts as a sink for both the
// stderr of this task and stderr of rustc itself, copying all the info onto
// the stderr channel we originally started with.
//
// The basic idea is to not use a default_handler() for rustc, and then also
// not print things by default to the actual stderr.
let (p, c) = Chan::new();
let w1 = io::ChanWriter::new(c);
let w2 = w1.clone();
let old = io::stdio::set_stderr(~w1);
spawn(proc() {
let mut p = io::PortReader::new(p);
let mut err = old.unwrap_or(~io::stderr() as ~Writer);
io::util::copy(&mut p, &mut err).unwrap();
});
let emitter = diagnostic::EmitterWriter::new(~w2);

// Compile the code
let diagnostic_handler = diagnostic::mk_handler(~emitter);
let span_diagnostic_handler =
diagnostic::mk_span_handler(diagnostic_handler, parsesess.cm);

@@ -126,6 +152,7 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool)
let cfg = driver::build_configuration(sess);
driver::compile_input(sess, cfg, &input, &out, &None);

// Run the code!
let exe = outdir.path().join("rust_out");
let out = Process::output(exe.as_str().unwrap(), []);
match out {
210 changes: 109 additions & 101 deletions src/libsyntax/diagnostic.rs
Original file line number Diff line number Diff line change
@@ -11,12 +11,10 @@
use codemap::{Pos, Span};
use codemap;

use std::cell::Cell;
use std::cell::{RefCell, Cell};
use std::fmt;
use std::io::stdio::StdWriter;
use std::io;
use std::iter::range;
use std::local_data;
use term;

static BUG_REPORT_URL: &'static str =
@@ -25,9 +23,9 @@ static BUG_REPORT_URL: &'static str =
static MAX_LINES: uint = 6u;

pub trait Emitter {
fn emit(&self, cmsp: Option<(&codemap::CodeMap, Span)>,
fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, Span)>,
msg: &str, lvl: Level);
fn custom_emit(&self, cm: &codemap::CodeMap,
fn custom_emit(&mut self, cm: &codemap::CodeMap,
sp: Span, msg: &str, lvl: Level);
}

@@ -78,16 +76,16 @@ impl SpanHandler {
// others log errors for later reporting.
pub struct Handler {
err_count: Cell<uint>,
emit: DefaultEmitter,
emit: RefCell<~Emitter>,
}
impl Handler {
pub fn fatal(&self, msg: &str) -> ! {
self.emit.emit(None, msg, Fatal);
self.emit.borrow_mut().get().emit(None, msg, Fatal);
fail!(FatalError);
}
pub fn err(&self, msg: &str) {
self.emit.emit(None, msg, Error);
self.emit.borrow_mut().get().emit(None, msg, Error);
self.bump_err_count();
}
pub fn bump_err_count(&self) {
@@ -112,10 +110,10 @@ impl Handler {
self.fatal(s);
}
pub fn warn(&self, msg: &str) {
self.emit.emit(None, msg, Warning);
self.emit.borrow_mut().get().emit(None, msg, Warning);
}
pub fn note(&self, msg: &str) {
self.emit.emit(None, msg, Note);
self.emit.borrow_mut().get().emit(None, msg, Note);
}
pub fn bug(&self, msg: &str) -> ! {
self.fatal(ice_msg(msg));
@@ -127,11 +125,11 @@ impl Handler {
cmsp: Option<(&codemap::CodeMap, Span)>,
msg: &str,
lvl: Level) {
self.emit.emit(cmsp, msg, lvl);
self.emit.borrow_mut().get().emit(cmsp, msg, lvl);
}
pub fn custom_emit(&self, cm: &codemap::CodeMap,
sp: Span, msg: &str, lvl: Level) {
self.emit.custom_emit(cm, sp, msg, lvl);
self.emit.borrow_mut().get().custom_emit(cm, sp, msg, lvl);
}
}
@@ -148,10 +146,14 @@ pub fn mk_span_handler(handler: @Handler, cm: @codemap::CodeMap)
}
}

pub fn mk_handler() -> @Handler {
pub fn default_handler() -> @Handler {
mk_handler(~EmitterWriter::stderr())
}

pub fn mk_handler(e: ~Emitter) -> @Handler {
@Handler {
err_count: Cell::new(0),
emit: DefaultEmitter,
emit: RefCell::new(e),
}
}

@@ -185,73 +187,79 @@ impl Level {
}
}

fn print_maybe_styled(msg: &str, color: term::attr::Attr) -> io::IoResult<()> {
local_data_key!(tls_terminal: Option<term::Terminal<StdWriter>>)


fn is_stderr_screen() -> bool {
use std::libc;
unsafe { libc::isatty(libc::STDERR_FILENO) != 0 }
}
fn write_pretty<T: Writer>(term: &mut term::Terminal<T>, s: &str,
c: term::attr::Attr) -> io::IoResult<()> {
try!(term.attr(c));
try!(term.write(s.as_bytes()));
try!(term.reset());
Ok(())
}

if is_stderr_screen() {
local_data::get_mut(tls_terminal, |term| {
match term {
Some(term) => {
match *term {
Some(ref mut term) => write_pretty(term, msg, color),
None => io::stderr().write(msg.as_bytes())
}
}
None => {
let (t, ret) = match term::Terminal::new(io::stderr()) {
Ok(mut term) => {
let r = write_pretty(&mut term, msg, color);
(Some(term), r)
}
Err(_) => {
(None, io::stderr().write(msg.as_bytes()))
}
};
local_data::set(tls_terminal, t);
ret
}
}
})
} else {
io::stderr().write(msg.as_bytes())
fn print_maybe_styled(w: &mut EmitterWriter,
msg: &str,
color: term::attr::Attr) -> io::IoResult<()> {
match w.dst {
Terminal(ref mut t) => {
try!(t.attr(color));
try!(t.write_str(msg));
try!(t.reset());
Ok(())
}
Raw(ref mut w) => {
w.write_str(msg)
}
}
}

fn print_diagnostic(topic: &str, lvl: Level, msg: &str) -> io::IoResult<()> {
fn print_diagnostic(dst: &mut EmitterWriter,
topic: &str, lvl: Level, msg: &str) -> io::IoResult<()> {
if !topic.is_empty() {
let mut stderr = io::stderr();
try!(write!(&mut stderr as &mut io::Writer, "{} ", topic));
try!(write!(&mut dst.dst, "{} ", topic));
}

try!(print_maybe_styled(format!("{}: ", lvl.to_str()),
term::attr::ForegroundColor(lvl.color())));
try!(print_maybe_styled(format!("{}\n", msg), term::attr::Bold));
try!(print_maybe_styled(dst, format!("{}: ", lvl.to_str()),
term::attr::ForegroundColor(lvl.color())));
try!(print_maybe_styled(dst, format!("{}\n", msg), term::attr::Bold));
Ok(())
}

pub struct DefaultEmitter;
pub struct EmitterWriter {
priv dst: Destination,
}

enum Destination {
Terminal(term::Terminal<io::stdio::StdWriter>),
Raw(~Writer),
}

impl EmitterWriter {
pub fn stderr() -> EmitterWriter {
let stderr = io::stderr();
if stderr.isatty() {
let dst = match term::Terminal::new(stderr) {
Ok(t) => Terminal(t),
Err(..) => Raw(~io::stderr()),
};
EmitterWriter { dst: dst }
} else {
EmitterWriter { dst: Raw(~stderr) }
}
}

pub fn new(dst: ~Writer) -> EmitterWriter {
EmitterWriter { dst: Raw(dst) }
}
}

impl Writer for Destination {
fn write(&mut self, bytes: &[u8]) -> io::IoResult<()> {
match *self {
Terminal(ref mut t) => t.write(bytes),
Raw(ref mut w) => w.write(bytes),
}
}
}

impl Emitter for DefaultEmitter {
fn emit(&self,
impl Emitter for EmitterWriter {
fn emit(&mut self,
cmsp: Option<(&codemap::CodeMap, Span)>,
msg: &str,
lvl: Level) {
let error = match cmsp {
Some((cm, sp)) => emit(cm, sp, msg, lvl, false),
None => print_diagnostic("", lvl, msg),
Some((cm, sp)) => emit(self, cm, sp, msg, lvl, false),
None => print_diagnostic(self, "", lvl, msg),
};

match error {
@@ -260,16 +268,16 @@ impl Emitter for DefaultEmitter {
}
}

fn custom_emit(&self, cm: &codemap::CodeMap,
fn custom_emit(&mut self, cm: &codemap::CodeMap,
sp: Span, msg: &str, lvl: Level) {
match emit(cm, sp, msg, lvl, true) {
match emit(self, cm, sp, msg, lvl, true) {
Ok(()) => {}
Err(e) => fail!("failed to print diagnostics: {}", e),
}
}
}

fn emit(cm: &codemap::CodeMap, sp: Span,
fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, sp: Span,
msg: &str, lvl: Level, custom: bool) -> io::IoResult<()> {
let ss = cm.span_to_str(sp);
let lines = cm.span_to_lines(sp);
@@ -279,22 +287,21 @@ fn emit(cm: &codemap::CodeMap, sp: Span,
// the span)
let span_end = Span { lo: sp.hi, hi: sp.hi, expn_info: sp.expn_info};
let ses = cm.span_to_str(span_end);
try!(print_diagnostic(ses, lvl, msg));
try!(custom_highlight_lines(cm, sp, lvl, lines));
try!(print_diagnostic(dst, ses, lvl, msg));
try!(custom_highlight_lines(dst, cm, sp, lvl, lines));
} else {
try!(print_diagnostic(ss, lvl, msg));
try!(highlight_lines(cm, sp, lvl, lines));
try!(print_diagnostic(dst, ss, lvl, msg));
try!(highlight_lines(dst, cm, sp, lvl, lines));
}
print_macro_backtrace(cm, sp)
print_macro_backtrace(dst, cm, sp)
}

fn highlight_lines(cm: &codemap::CodeMap,
fn highlight_lines(err: &mut EmitterWriter,
cm: &codemap::CodeMap,
sp: Span,
lvl: Level,
lines: &codemap::FileLines) -> io::IoResult<()> {
let fm = lines.file;
let mut err = io::stderr();
let err = &mut err as &mut io::Writer;

let mut elided = false;
let mut display_lines = lines.lines.as_slice();
@@ -304,13 +311,13 @@ fn highlight_lines(cm: &codemap::CodeMap,
}
// Print the offending lines
for line in display_lines.iter() {
try!(write!(err, "{}:{} {}\n", fm.name, *line + 1,
fm.get_line(*line as int)));
try!(write!(&mut err.dst, "{}:{} {}\n", fm.name, *line + 1,
fm.get_line(*line as int)));
}
if elided {
let last_line = display_lines[display_lines.len() - 1u];
let s = format!("{}:{} ", fm.name, last_line + 1u);
try!(write!(err, "{0:1$}...\n", "", s.len()));
try!(write!(&mut err.dst, "{0:1$}...\n", "", s.len()));
}

// FIXME (#3260)
@@ -342,16 +349,16 @@ fn highlight_lines(cm: &codemap::CodeMap,
_ => s.push_char(' '),
};
}
try!(write!(err, "{}", s));
try!(write!(&mut err.dst, "{}", s));
let mut s = ~"^";
let hi = cm.lookup_char_pos(sp.hi);
if hi.col != lo.col {
// the ^ already takes up one space
let num_squigglies = hi.col.to_uint()-lo.col.to_uint()-1u;
for _ in range(0, num_squigglies) { s.push_char('~'); }
}
try!(print_maybe_styled(s + "\n",
term::attr::ForegroundColor(lvl.color())));
try!(print_maybe_styled(err, s + "\n",
term::attr::ForegroundColor(lvl.color())));
}
Ok(())
}
@@ -362,26 +369,25 @@ fn highlight_lines(cm: &codemap::CodeMap,
// than 6 lines), `custom_highlight_lines` will print the first line, then
// dot dot dot, then last line, whereas `highlight_lines` prints the first
// six lines.
fn custom_highlight_lines(cm: &codemap::CodeMap,
fn custom_highlight_lines(w: &mut EmitterWriter,
cm: &codemap::CodeMap,
sp: Span,
lvl: Level,
lines: &codemap::FileLines) -> io::IoResult<()> {
let fm = lines.file;
let mut err = io::stderr();
let err = &mut err as &mut io::Writer;

let lines = lines.lines.as_slice();
if lines.len() > MAX_LINES {
try!(write!(err, "{}:{} {}\n", fm.name,
lines[0] + 1, fm.get_line(lines[0] as int)));
try!(write!(err, "...\n"));
try!(write!(&mut w.dst, "{}:{} {}\n", fm.name,
lines[0] + 1, fm.get_line(lines[0] as int)));
try!(write!(&mut w.dst, "...\n"));
let last_line = lines[lines.len()-1];
try!(write!(err, "{}:{} {}\n", fm.name,
last_line + 1, fm.get_line(last_line as int)));
try!(write!(&mut w.dst, "{}:{} {}\n", fm.name,
last_line + 1, fm.get_line(last_line as int)));
} else {
for line in lines.iter() {
try!(write!(err, "{}:{} {}\n", fm.name,
*line + 1, fm.get_line(*line as int)));
try!(write!(&mut w.dst, "{}:{} {}\n", fm.name,
*line + 1, fm.get_line(*line as int)));
}
}
let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1]+1);
@@ -391,22 +397,24 @@ fn custom_highlight_lines(cm: &codemap::CodeMap,
let mut s = ~"";
for _ in range(0, skip) { s.push_char(' '); }
s.push_char('^');
print_maybe_styled(s + "\n", term::attr::ForegroundColor(lvl.color()))
print_maybe_styled(w, s + "\n", term::attr::ForegroundColor(lvl.color()))
}

fn print_macro_backtrace(cm: &codemap::CodeMap, sp: Span) -> io::IoResult<()> {
fn print_macro_backtrace(w: &mut EmitterWriter,
cm: &codemap::CodeMap,
sp: Span) -> io::IoResult<()> {
for ei in sp.expn_info.iter() {
let ss = ei.callee.span.as_ref().map_or(~"", |span| cm.span_to_str(*span));
let (pre, post) = match ei.callee.format {
codemap::MacroAttribute => ("#[", "]"),
codemap::MacroBang => ("", "!")
};
try!(print_diagnostic(ss, Note,
format!("in expansion of {}{}{}", pre,
ei.callee.name, post)));
try!(print_diagnostic(w, ss, Note,
format!("in expansion of {}{}{}", pre,
ei.callee.name, post)));
let ss = cm.span_to_str(ei.call_site);
try!(print_diagnostic(ss, Note, "expansion site"));
try!(print_macro_backtrace(cm, ei.call_site));
try!(print_diagnostic(w, ss, Note, "expansion site"));
try!(print_macro_backtrace(w, cm, ei.call_site));
}
Ok(())
}
6 changes: 5 additions & 1 deletion src/libsyntax/parse/lexer.rs
Original file line number Diff line number Diff line change
@@ -1004,6 +1004,7 @@ mod test {
use diagnostic;
use parse::token;
use parse::token::{str_to_ident};
use std::io::util;

// represents a testing reader (incl. both reader and interner)
struct Env {
@@ -1014,7 +1015,10 @@ mod test {
fn setup(teststr: ~str) -> Env {
let cm = CodeMap::new();
let fm = cm.new_filemap(~"zebra.rs", teststr);
let span_handler = diagnostic::mk_span_handler(diagnostic::mk_handler(), @cm);
let writer = ~util::NullWriter;
let emitter = diagnostic::EmitterWriter::new(writer);
let handler = diagnostic::mk_handler(~emitter);
let span_handler = diagnostic::mk_span_handler(handler, @cm);
Env {
string_reader: new_string_reader(span_handler,fm)
}
4 changes: 2 additions & 2 deletions src/libsyntax/parse/mod.rs
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
use ast;
use codemap::{Span, CodeMap, FileMap};
use codemap;
use diagnostic::{SpanHandler, mk_span_handler, mk_handler};
use diagnostic::{SpanHandler, mk_span_handler, default_handler};
use parse::attr::ParserAttr;
use parse::parser::Parser;

@@ -49,7 +49,7 @@ pub fn new_parse_sess() -> @ParseSess {
let cm = @CodeMap::new();
@ParseSess {
cm: cm,
span_diagnostic: mk_span_handler(mk_handler(), cm),
span_diagnostic: mk_span_handler(default_handler(), cm),
included_mod_stack: RefCell::new(~[]),
}
}