Add scaffolding for assigning alpha-numeric codes to rustc diagnostics
This commit is contained in:
parent
7ab9bfab4e
commit
9b9cce2316
25 changed files with 468 additions and 86 deletions
18
src/librustc/diagnostics.rs
Normal file
18
src/librustc/diagnostics.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
register_diagnostic!(E0001, r##"
|
||||||
|
This error suggests that the expression arm corresponding to the noted pattern
|
||||||
|
will never be reached as for all possible values of the expression being matched,
|
||||||
|
one of the preceeding patterns will match.
|
||||||
|
|
||||||
|
This means that perhaps some of the preceeding patterns are too general, this
|
||||||
|
one is too specific or the ordering is incorrect.
|
||||||
|
"##)
|
|
@ -532,6 +532,7 @@ pub fn optgroups() -> Vec<getopts::OptGroup> {
|
||||||
optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
|
optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
|
||||||
optopt( "", "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
|
optopt( "", "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
|
||||||
optflag("", "parse-only", "Parse only; do not compile, assemble, or link"),
|
optflag("", "parse-only", "Parse only; do not compile, assemble, or link"),
|
||||||
|
optopt("", "explain", "Provide a detailed explanation of an error message", "OPT"),
|
||||||
optflagopt("", "pretty",
|
optflagopt("", "pretty",
|
||||||
"Pretty-print the input instead of compiling;
|
"Pretty-print the input instead of compiling;
|
||||||
valid types are: `normal` (un-annotated source),
|
valid types are: `normal` (un-annotated source),
|
||||||
|
@ -807,6 +808,7 @@ mod test {
|
||||||
use getopts::getopts;
|
use getopts::getopts;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::attr::AttrMetaMethods;
|
use syntax::attr::AttrMetaMethods;
|
||||||
|
use syntax::diagnostics;
|
||||||
|
|
||||||
// When the user supplies --test we should implicitly supply --cfg test
|
// When the user supplies --test we should implicitly supply --cfg test
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -816,8 +818,9 @@ mod test {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(f) => fail!("test_switch_implies_cfg_test: {}", f)
|
Err(f) => fail!("test_switch_implies_cfg_test: {}", f)
|
||||||
};
|
};
|
||||||
|
let registry = diagnostics::registry::Registry::new([]);
|
||||||
let sessopts = build_session_options(matches);
|
let sessopts = build_session_options(matches);
|
||||||
let sess = build_session(sessopts, None);
|
let sess = build_session(sessopts, None, registry);
|
||||||
let cfg = build_configuration(&sess);
|
let cfg = build_configuration(&sess);
|
||||||
assert!((attr::contains_name(cfg.as_slice(), "test")));
|
assert!((attr::contains_name(cfg.as_slice(), "test")));
|
||||||
}
|
}
|
||||||
|
@ -834,8 +837,9 @@ mod test {
|
||||||
fail!("test_switch_implies_cfg_test_unless_cfg_test: {}", f)
|
fail!("test_switch_implies_cfg_test_unless_cfg_test: {}", f)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let registry = diagnostics::registry::Registry::new([]);
|
||||||
let sessopts = build_session_options(matches);
|
let sessopts = build_session_options(matches);
|
||||||
let sess = build_session(sessopts, None);
|
let sess = build_session(sessopts, None, registry);
|
||||||
let cfg = build_configuration(&sess);
|
let cfg = build_configuration(&sess);
|
||||||
let mut test_items = cfg.iter().filter(|m| m.name().equiv(&("test")));
|
let mut test_items = cfg.iter().filter(|m| m.name().equiv(&("test")));
|
||||||
assert!(test_items.next().is_some());
|
assert!(test_items.next().is_some());
|
||||||
|
|
|
@ -16,6 +16,7 @@ use driver::{PpmFlowGraph, PpmExpanded, PpmExpandedIdentified, PpmTyped};
|
||||||
use driver::{PpmIdentified};
|
use driver::{PpmIdentified};
|
||||||
use front;
|
use front;
|
||||||
use lib::llvm::{ContextRef, ModuleRef};
|
use lib::llvm::{ContextRef, ModuleRef};
|
||||||
|
use lint;
|
||||||
use metadata::common::LinkMeta;
|
use metadata::common::LinkMeta;
|
||||||
use metadata::creader;
|
use metadata::creader;
|
||||||
use middle::cfg;
|
use middle::cfg;
|
||||||
|
@ -26,7 +27,7 @@ use middle;
|
||||||
use plugin::load::Plugins;
|
use plugin::load::Plugins;
|
||||||
use plugin::registry::Registry;
|
use plugin::registry::Registry;
|
||||||
use plugin;
|
use plugin;
|
||||||
use lint;
|
|
||||||
use util::common::time;
|
use util::common::time;
|
||||||
use util::ppaux;
|
use util::ppaux;
|
||||||
use util::nodemap::{NodeSet};
|
use util::nodemap::{NodeSet};
|
||||||
|
@ -41,6 +42,7 @@ use std::io::MemReader;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::attr::{AttrMetaMethods};
|
use syntax::attr::{AttrMetaMethods};
|
||||||
|
use syntax::diagnostics;
|
||||||
use syntax::parse;
|
use syntax::parse;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::print::{pp, pprust};
|
use syntax::print::{pp, pprust};
|
||||||
|
@ -213,6 +215,15 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
||||||
let mut registry = Registry::new(&krate);
|
let mut registry = Registry::new(&krate);
|
||||||
|
|
||||||
time(time_passes, "plugin registration", (), |_| {
|
time(time_passes, "plugin registration", (), |_| {
|
||||||
|
if sess.features.rustc_diagnostic_macros.get() {
|
||||||
|
registry.register_macro("__diagnostic_used",
|
||||||
|
diagnostics::plugin::expand_diagnostic_used);
|
||||||
|
registry.register_macro("__register_diagnostic",
|
||||||
|
diagnostics::plugin::expand_register_diagnostic);
|
||||||
|
registry.register_macro("__build_diagnostic_array",
|
||||||
|
diagnostics::plugin::expand_build_diagnostic_array);
|
||||||
|
}
|
||||||
|
|
||||||
for ®istrar in registrars.iter() {
|
for ®istrar in registrars.iter() {
|
||||||
registrar(&mut registry);
|
registrar(&mut registry);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ use std::task::TaskBuilder;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::parse;
|
use syntax::parse;
|
||||||
use syntax::diagnostic::Emitter;
|
use syntax::diagnostic::Emitter;
|
||||||
|
use syntax::diagnostics;
|
||||||
|
|
||||||
use getopts;
|
use getopts;
|
||||||
|
|
||||||
|
@ -49,8 +50,24 @@ fn run_compiler(args: &[String]) {
|
||||||
Some(matches) => matches,
|
Some(matches) => matches,
|
||||||
None => return
|
None => return
|
||||||
};
|
};
|
||||||
let sopts = config::build_session_options(&matches);
|
|
||||||
|
|
||||||
|
let descriptions = diagnostics::registry::Registry::new(super::DIAGNOSTICS);
|
||||||
|
match matches.opt_str("explain") {
|
||||||
|
Some(ref code) => {
|
||||||
|
match descriptions.find_description(code.as_slice()) {
|
||||||
|
Some(ref description) => {
|
||||||
|
println!("{}", description);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
early_error(format!("no extended information for {}", code).as_slice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
None => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
let sopts = config::build_session_options(&matches);
|
||||||
let (input, input_file_path) = match matches.free.len() {
|
let (input, input_file_path) = match matches.free.len() {
|
||||||
0u => {
|
0u => {
|
||||||
if sopts.describe_lints {
|
if sopts.describe_lints {
|
||||||
|
@ -75,7 +92,7 @@ fn run_compiler(args: &[String]) {
|
||||||
_ => early_error("multiple input filenames provided")
|
_ => early_error("multiple input filenames provided")
|
||||||
};
|
};
|
||||||
|
|
||||||
let sess = build_session(sopts, input_file_path);
|
let sess = build_session(sopts, input_file_path, descriptions);
|
||||||
let cfg = config::build_configuration(&sess);
|
let cfg = config::build_configuration(&sess);
|
||||||
let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
|
let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
|
||||||
let ofile = matches.opt_str("o").map(|o| Path::new(o));
|
let ofile = matches.opt_str("o").map(|o| Path::new(o));
|
||||||
|
@ -383,14 +400,14 @@ fn parse_crate_attrs(sess: &Session, input: &Input) ->
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn early_error(msg: &str) -> ! {
|
pub fn early_error(msg: &str) -> ! {
|
||||||
let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto);
|
let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None);
|
||||||
emitter.emit(None, msg, diagnostic::Fatal);
|
emitter.emit(None, msg, None, diagnostic::Fatal);
|
||||||
fail!(diagnostic::FatalError);
|
fail!(diagnostic::FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn early_warn(msg: &str) {
|
pub fn early_warn(msg: &str) {
|
||||||
let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto);
|
let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None);
|
||||||
emitter.emit(None, msg, diagnostic::Warning);
|
emitter.emit(None, msg, None, diagnostic::Warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_metadata(sess: &Session, path: &Path,
|
pub fn list_metadata(sess: &Session, path: &Path,
|
||||||
|
@ -429,7 +446,7 @@ fn monitor(f: proc():Send) {
|
||||||
Err(value) => {
|
Err(value) => {
|
||||||
// Task failed without emitting a fatal diagnostic
|
// Task failed without emitting a fatal diagnostic
|
||||||
if !value.is::<diagnostic::FatalError>() {
|
if !value.is::<diagnostic::FatalError>() {
|
||||||
let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto);
|
let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None);
|
||||||
|
|
||||||
// a .span_bug or .bug call has already printed what
|
// a .span_bug or .bug call has already printed what
|
||||||
// it wants to print.
|
// it wants to print.
|
||||||
|
@ -437,6 +454,7 @@ fn monitor(f: proc():Send) {
|
||||||
emitter.emit(
|
emitter.emit(
|
||||||
None,
|
None,
|
||||||
"unexpected failure",
|
"unexpected failure",
|
||||||
|
None,
|
||||||
diagnostic::Bug);
|
diagnostic::Bug);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,7 +465,7 @@ fn monitor(f: proc():Send) {
|
||||||
"run with `RUST_BACKTRACE=1` for a backtrace".to_string(),
|
"run with `RUST_BACKTRACE=1` for a backtrace".to_string(),
|
||||||
];
|
];
|
||||||
for note in xs.iter() {
|
for note in xs.iter() {
|
||||||
emitter.emit(None, note.as_slice(), diagnostic::Note)
|
emitter.emit(None, note.as_slice(), None, diagnostic::Note)
|
||||||
}
|
}
|
||||||
|
|
||||||
match r.read_to_string() {
|
match r.read_to_string() {
|
||||||
|
@ -457,6 +475,7 @@ fn monitor(f: proc():Send) {
|
||||||
format!("failed to read internal \
|
format!("failed to read internal \
|
||||||
stderr: {}",
|
stderr: {}",
|
||||||
e).as_slice(),
|
e).as_slice(),
|
||||||
|
None,
|
||||||
diagnostic::Error)
|
diagnostic::Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ use util::nodemap::NodeMap;
|
||||||
use syntax::ast::NodeId;
|
use syntax::ast::NodeId;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::diagnostic;
|
use syntax::diagnostic;
|
||||||
|
use syntax::diagnostics;
|
||||||
use syntax::parse;
|
use syntax::parse;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::parse::ParseSess;
|
use syntax::parse::ParseSess;
|
||||||
|
@ -65,6 +66,9 @@ impl Session {
|
||||||
pub fn span_err(&self, sp: Span, msg: &str) {
|
pub fn span_err(&self, sp: Span, msg: &str) {
|
||||||
self.diagnostic().span_err(sp, msg)
|
self.diagnostic().span_err(sp, msg)
|
||||||
}
|
}
|
||||||
|
pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) {
|
||||||
|
self.diagnostic().span_err_with_code(sp, msg, code)
|
||||||
|
}
|
||||||
pub fn err(&self, msg: &str) {
|
pub fn err(&self, msg: &str) {
|
||||||
self.diagnostic().handler().err(msg)
|
self.diagnostic().handler().err(msg)
|
||||||
}
|
}
|
||||||
|
@ -197,11 +201,12 @@ impl Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_session(sopts: config::Options,
|
pub fn build_session(sopts: config::Options,
|
||||||
local_crate_source_file: Option<Path>)
|
local_crate_source_file: Option<Path>,
|
||||||
|
registry: diagnostics::registry::Registry)
|
||||||
-> Session {
|
-> Session {
|
||||||
let codemap = codemap::CodeMap::new();
|
let codemap = codemap::CodeMap::new();
|
||||||
let diagnostic_handler =
|
let diagnostic_handler =
|
||||||
diagnostic::default_handler(sopts.color);
|
diagnostic::default_handler(sopts.color, Some(registry));
|
||||||
let span_diagnostic_handler =
|
let span_diagnostic_handler =
|
||||||
diagnostic::mk_span_handler(diagnostic_handler, codemap);
|
diagnostic::mk_span_handler(diagnostic_handler, codemap);
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,8 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
|
||||||
|
|
||||||
("quad_precision_float", Removed),
|
("quad_precision_float", Removed),
|
||||||
|
|
||||||
|
("rustc_diagnostic_macros", Active),
|
||||||
|
|
||||||
// A temporary feature gate used to enable parser extensions needed
|
// A temporary feature gate used to enable parser extensions needed
|
||||||
// to bootstrap fix for #5723.
|
// to bootstrap fix for #5723.
|
||||||
("issue_5723_bootstrap", Active),
|
("issue_5723_bootstrap", Active),
|
||||||
|
@ -93,6 +95,7 @@ pub struct Features {
|
||||||
pub default_type_params: Cell<bool>,
|
pub default_type_params: Cell<bool>,
|
||||||
pub issue_5723_bootstrap: Cell<bool>,
|
pub issue_5723_bootstrap: Cell<bool>,
|
||||||
pub overloaded_calls: Cell<bool>,
|
pub overloaded_calls: Cell<bool>,
|
||||||
|
pub rustc_diagnostic_macros: Cell<bool>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Features {
|
impl Features {
|
||||||
|
@ -101,6 +104,7 @@ impl Features {
|
||||||
default_type_params: Cell::new(false),
|
default_type_params: Cell::new(false),
|
||||||
issue_5723_bootstrap: Cell::new(false),
|
issue_5723_bootstrap: Cell::new(false),
|
||||||
overloaded_calls: Cell::new(false),
|
overloaded_calls: Cell::new(false),
|
||||||
|
rustc_diagnostic_macros: Cell::new(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -425,4 +429,5 @@ pub fn check_crate(sess: &Session, krate: &ast::Crate) {
|
||||||
sess.features.default_type_params.set(cx.has_feature("default_type_params"));
|
sess.features.default_type_params.set(cx.has_feature("default_type_params"));
|
||||||
sess.features.issue_5723_bootstrap.set(cx.has_feature("issue_5723_bootstrap"));
|
sess.features.issue_5723_bootstrap.set(cx.has_feature("issue_5723_bootstrap"));
|
||||||
sess.features.overloaded_calls.set(cx.has_feature("overloaded_calls"));
|
sess.features.overloaded_calls.set(cx.has_feature("overloaded_calls"));
|
||||||
|
sess.features.rustc_diagnostic_macros.set(cx.has_feature("rustc_diagnostic_macros"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,9 @@ This API is completely unstable and subject to change.
|
||||||
#![feature(macro_rules, globs, struct_variant, managed_boxes, quote)]
|
#![feature(macro_rules, globs, struct_variant, managed_boxes, quote)]
|
||||||
#![feature(default_type_params, phase, unsafe_destructor)]
|
#![feature(default_type_params, phase, unsafe_destructor)]
|
||||||
|
|
||||||
|
#![allow(unknown_features)] // NOTE: Remove after next snapshot
|
||||||
|
#![feature(rustc_diagnostic_macros)]
|
||||||
|
|
||||||
extern crate arena;
|
extern crate arena;
|
||||||
extern crate debug;
|
extern crate debug;
|
||||||
extern crate flate;
|
extern crate flate;
|
||||||
|
@ -39,9 +42,11 @@ extern crate getopts;
|
||||||
extern crate graphviz;
|
extern crate graphviz;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
extern crate serialize;
|
extern crate serialize;
|
||||||
extern crate syntax;
|
|
||||||
extern crate time;
|
extern crate time;
|
||||||
#[phase(plugin, link)] extern crate log;
|
#[phase(plugin, link)] extern crate log;
|
||||||
|
#[phase(plugin, link)] extern crate syntax;
|
||||||
|
|
||||||
|
mod diagnostics;
|
||||||
|
|
||||||
pub mod middle {
|
pub mod middle {
|
||||||
pub mod def;
|
pub mod def;
|
||||||
|
@ -127,6 +132,8 @@ pub mod lib {
|
||||||
pub mod llvmdeps;
|
pub mod llvmdeps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__build_diagnostic_array!(DIAGNOSTICS)
|
||||||
|
|
||||||
// A private module so that macro-expanded idents like
|
// A private module so that macro-expanded idents like
|
||||||
// `::rustc::lint::Lint` will also work in `rustc` itself.
|
// `::rustc::lint::Lint` will also work in `rustc` itself.
|
||||||
//
|
//
|
||||||
|
|
|
@ -194,7 +194,7 @@ fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) {
|
||||||
|
|
||||||
let v = vec!(*pat);
|
let v = vec!(*pat);
|
||||||
match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) {
|
match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) {
|
||||||
NotUseful => cx.tcx.sess.span_err(pat.span, "unreachable pattern"),
|
NotUseful => span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern"),
|
||||||
Useful => (),
|
Useful => (),
|
||||||
UsefulWithWitness(_) => unreachable!()
|
UsefulWithWitness(_) => unreachable!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,7 @@ impl Emitter for ExpectErrorEmitter {
|
||||||
fn emit(&mut self,
|
fn emit(&mut self,
|
||||||
_cmsp: Option<(&codemap::CodeMap, Span)>,
|
_cmsp: Option<(&codemap::CodeMap, Span)>,
|
||||||
msg: &str,
|
msg: &str,
|
||||||
|
_: Option<&str>,
|
||||||
lvl: Level)
|
lvl: Level)
|
||||||
{
|
{
|
||||||
remove_message(self, msg, lvl);
|
remove_message(self, msg, lvl);
|
||||||
|
|
|
@ -101,7 +101,7 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<String>)
|
||||||
|
|
||||||
|
|
||||||
let codemap = syntax::codemap::CodeMap::new();
|
let codemap = syntax::codemap::CodeMap::new();
|
||||||
let diagnostic_handler = syntax::diagnostic::default_handler(syntax::diagnostic::Auto);
|
let diagnostic_handler = syntax::diagnostic::default_handler(syntax::diagnostic::Auto, None);
|
||||||
let span_diagnostic_handler =
|
let span_diagnostic_handler =
|
||||||
syntax::diagnostic::mk_span_handler(diagnostic_handler, codemap);
|
syntax::diagnostic::mk_span_handler(diagnostic_handler, codemap);
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ pub fn run(input: &str,
|
||||||
|
|
||||||
|
|
||||||
let codemap = CodeMap::new();
|
let codemap = CodeMap::new();
|
||||||
let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto);
|
let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto, None);
|
||||||
let span_diagnostic_handler =
|
let span_diagnostic_handler =
|
||||||
diagnostic::mk_span_handler(diagnostic_handler, codemap);
|
diagnostic::mk_span_handler(diagnostic_handler, codemap);
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool,
|
||||||
};
|
};
|
||||||
io::util::copy(&mut p, &mut err).unwrap();
|
io::util::copy(&mut p, &mut err).unwrap();
|
||||||
});
|
});
|
||||||
let emitter = diagnostic::EmitterWriter::new(box w2);
|
let emitter = diagnostic::EmitterWriter::new(box w2, None);
|
||||||
|
|
||||||
// Compile the code
|
// Compile the code
|
||||||
let codemap = CodeMap::new();
|
let codemap = CodeMap::new();
|
||||||
|
|
|
@ -12,6 +12,7 @@ extern crate libc;
|
||||||
|
|
||||||
use codemap::{Pos, Span};
|
use codemap::{Pos, Span};
|
||||||
use codemap;
|
use codemap;
|
||||||
|
use diagnostics;
|
||||||
|
|
||||||
use std::cell::{RefCell, Cell};
|
use std::cell::{RefCell, Cell};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -59,7 +60,7 @@ pub enum ColorConfig {
|
||||||
|
|
||||||
pub trait Emitter {
|
pub trait Emitter {
|
||||||
fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, Span)>,
|
fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, Span)>,
|
||||||
msg: &str, lvl: Level);
|
msg: &str, code: Option<&str>, lvl: Level);
|
||||||
fn custom_emit(&mut self, cm: &codemap::CodeMap,
|
fn custom_emit(&mut self, cm: &codemap::CodeMap,
|
||||||
sp: RenderSpan, msg: &str, lvl: Level);
|
sp: RenderSpan, msg: &str, lvl: Level);
|
||||||
}
|
}
|
||||||
|
@ -90,6 +91,10 @@ impl SpanHandler {
|
||||||
self.handler.emit(Some((&self.cm, sp)), msg, Error);
|
self.handler.emit(Some((&self.cm, sp)), msg, Error);
|
||||||
self.handler.bump_err_count();
|
self.handler.bump_err_count();
|
||||||
}
|
}
|
||||||
|
pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) {
|
||||||
|
self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Error);
|
||||||
|
self.handler.bump_err_count();
|
||||||
|
}
|
||||||
pub fn span_warn(&self, sp: Span, msg: &str) {
|
pub fn span_warn(&self, sp: Span, msg: &str) {
|
||||||
self.handler.emit(Some((&self.cm, sp)), msg, Warning);
|
self.handler.emit(Some((&self.cm, sp)), msg, Warning);
|
||||||
}
|
}
|
||||||
|
@ -124,11 +129,11 @@ pub struct Handler {
|
||||||
|
|
||||||
impl Handler {
|
impl Handler {
|
||||||
pub fn fatal(&self, msg: &str) -> ! {
|
pub fn fatal(&self, msg: &str) -> ! {
|
||||||
self.emit.borrow_mut().emit(None, msg, Fatal);
|
self.emit.borrow_mut().emit(None, msg, None, Fatal);
|
||||||
fail!(FatalError);
|
fail!(FatalError);
|
||||||
}
|
}
|
||||||
pub fn err(&self, msg: &str) {
|
pub fn err(&self, msg: &str) {
|
||||||
self.emit.borrow_mut().emit(None, msg, Error);
|
self.emit.borrow_mut().emit(None, msg, None, Error);
|
||||||
self.bump_err_count();
|
self.bump_err_count();
|
||||||
}
|
}
|
||||||
pub fn bump_err_count(&self) {
|
pub fn bump_err_count(&self) {
|
||||||
|
@ -153,13 +158,13 @@ impl Handler {
|
||||||
self.fatal(s.as_slice());
|
self.fatal(s.as_slice());
|
||||||
}
|
}
|
||||||
pub fn warn(&self, msg: &str) {
|
pub fn warn(&self, msg: &str) {
|
||||||
self.emit.borrow_mut().emit(None, msg, Warning);
|
self.emit.borrow_mut().emit(None, msg, None, Warning);
|
||||||
}
|
}
|
||||||
pub fn note(&self, msg: &str) {
|
pub fn note(&self, msg: &str) {
|
||||||
self.emit.borrow_mut().emit(None, msg, Note);
|
self.emit.borrow_mut().emit(None, msg, None, Note);
|
||||||
}
|
}
|
||||||
pub fn bug(&self, msg: &str) -> ! {
|
pub fn bug(&self, msg: &str) -> ! {
|
||||||
self.emit.borrow_mut().emit(None, msg, Bug);
|
self.emit.borrow_mut().emit(None, msg, None, Bug);
|
||||||
fail!(ExplicitBug);
|
fail!(ExplicitBug);
|
||||||
}
|
}
|
||||||
pub fn unimpl(&self, msg: &str) -> ! {
|
pub fn unimpl(&self, msg: &str) -> ! {
|
||||||
|
@ -169,7 +174,14 @@ impl Handler {
|
||||||
cmsp: Option<(&codemap::CodeMap, Span)>,
|
cmsp: Option<(&codemap::CodeMap, Span)>,
|
||||||
msg: &str,
|
msg: &str,
|
||||||
lvl: Level) {
|
lvl: Level) {
|
||||||
self.emit.borrow_mut().emit(cmsp, msg, lvl);
|
self.emit.borrow_mut().emit(cmsp, msg, None, lvl);
|
||||||
|
}
|
||||||
|
pub fn emit_with_code(&self,
|
||||||
|
cmsp: Option<(&codemap::CodeMap, Span)>,
|
||||||
|
msg: &str,
|
||||||
|
code: &str,
|
||||||
|
lvl: Level) {
|
||||||
|
self.emit.borrow_mut().emit(cmsp, msg, Some(code), lvl);
|
||||||
}
|
}
|
||||||
pub fn custom_emit(&self, cm: &codemap::CodeMap,
|
pub fn custom_emit(&self, cm: &codemap::CodeMap,
|
||||||
sp: RenderSpan, msg: &str, lvl: Level) {
|
sp: RenderSpan, msg: &str, lvl: Level) {
|
||||||
|
@ -184,8 +196,9 @@ pub fn mk_span_handler(handler: Handler, cm: codemap::CodeMap) -> SpanHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_handler(color_config: ColorConfig) -> Handler {
|
pub fn default_handler(color_config: ColorConfig,
|
||||||
mk_handler(box EmitterWriter::stderr(color_config))
|
registry: Option<diagnostics::registry::Registry>) -> Handler {
|
||||||
|
mk_handler(box EmitterWriter::stderr(color_config, registry))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mk_handler(e: Box<Emitter + Send>) -> Handler {
|
pub fn mk_handler(e: Box<Emitter + Send>) -> Handler {
|
||||||
|
@ -262,8 +275,8 @@ fn print_maybe_styled(w: &mut EmitterWriter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_diagnostic(dst: &mut EmitterWriter,
|
fn print_diagnostic(dst: &mut EmitterWriter, topic: &str, lvl: Level,
|
||||||
topic: &str, lvl: Level, msg: &str) -> io::IoResult<()> {
|
msg: &str, code: Option<&str>) -> io::IoResult<()> {
|
||||||
if !topic.is_empty() {
|
if !topic.is_empty() {
|
||||||
try!(write!(&mut dst.dst, "{} ", topic));
|
try!(write!(&mut dst.dst, "{} ", topic));
|
||||||
}
|
}
|
||||||
|
@ -272,13 +285,32 @@ fn print_diagnostic(dst: &mut EmitterWriter,
|
||||||
format!("{}: ", lvl.to_string()).as_slice(),
|
format!("{}: ", lvl.to_string()).as_slice(),
|
||||||
term::attr::ForegroundColor(lvl.color())));
|
term::attr::ForegroundColor(lvl.color())));
|
||||||
try!(print_maybe_styled(dst,
|
try!(print_maybe_styled(dst,
|
||||||
format!("{}\n", msg).as_slice(),
|
format!("{}", msg).as_slice(),
|
||||||
term::attr::Bold));
|
term::attr::Bold));
|
||||||
|
|
||||||
|
match code {
|
||||||
|
Some(code) => {
|
||||||
|
let style = term::attr::ForegroundColor(term::color::BRIGHT_MAGENTA);
|
||||||
|
try!(print_maybe_styled(dst, format!(" [{}]", code.clone()).as_slice(), style));
|
||||||
|
match dst.registry.as_ref().and_then(|registry| registry.find_description(code)) {
|
||||||
|
Some(_) => {
|
||||||
|
try!(write!(&mut dst.dst,
|
||||||
|
" (pass `--explain {}` to see a detailed explanation)",
|
||||||
|
code
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => ()
|
||||||
|
}
|
||||||
|
try!(dst.dst.write_char('\n'));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EmitterWriter {
|
pub struct EmitterWriter {
|
||||||
dst: Destination,
|
dst: Destination,
|
||||||
|
registry: Option<diagnostics::registry::Registry>
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Destination {
|
enum Destination {
|
||||||
|
@ -287,7 +319,8 @@ enum Destination {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EmitterWriter {
|
impl EmitterWriter {
|
||||||
pub fn stderr(color_config: ColorConfig) -> EmitterWriter {
|
pub fn stderr(color_config: ColorConfig,
|
||||||
|
registry: Option<diagnostics::registry::Registry>) -> EmitterWriter {
|
||||||
let stderr = io::stderr();
|
let stderr = io::stderr();
|
||||||
|
|
||||||
let use_color = match color_config {
|
let use_color = match color_config {
|
||||||
|
@ -301,14 +334,15 @@ impl EmitterWriter {
|
||||||
Some(t) => Terminal(t),
|
Some(t) => Terminal(t),
|
||||||
None => Raw(box stderr),
|
None => Raw(box stderr),
|
||||||
};
|
};
|
||||||
EmitterWriter { dst: dst }
|
EmitterWriter { dst: dst, registry: registry }
|
||||||
} else {
|
} else {
|
||||||
EmitterWriter { dst: Raw(box stderr) }
|
EmitterWriter { dst: Raw(box stderr), registry: registry }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(dst: Box<Writer + Send>) -> EmitterWriter {
|
pub fn new(dst: Box<Writer + Send>,
|
||||||
EmitterWriter { dst: Raw(dst) }
|
registry: Option<diagnostics::registry::Registry>) -> EmitterWriter {
|
||||||
|
EmitterWriter { dst: Raw(dst), registry: registry }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,11 +358,10 @@ impl Writer for Destination {
|
||||||
impl Emitter for EmitterWriter {
|
impl Emitter for EmitterWriter {
|
||||||
fn emit(&mut self,
|
fn emit(&mut self,
|
||||||
cmsp: Option<(&codemap::CodeMap, Span)>,
|
cmsp: Option<(&codemap::CodeMap, Span)>,
|
||||||
msg: &str,
|
msg: &str, code: Option<&str>, lvl: Level) {
|
||||||
lvl: Level) {
|
|
||||||
let error = match cmsp {
|
let error = match cmsp {
|
||||||
Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, lvl, false),
|
Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, code, lvl, false),
|
||||||
None => print_diagnostic(self, "", lvl, msg),
|
None => print_diagnostic(self, "", lvl, msg, code),
|
||||||
};
|
};
|
||||||
|
|
||||||
match error {
|
match error {
|
||||||
|
@ -339,7 +372,7 @@ impl Emitter for EmitterWriter {
|
||||||
|
|
||||||
fn custom_emit(&mut self, cm: &codemap::CodeMap,
|
fn custom_emit(&mut self, cm: &codemap::CodeMap,
|
||||||
sp: RenderSpan, msg: &str, lvl: Level) {
|
sp: RenderSpan, msg: &str, lvl: Level) {
|
||||||
match emit(self, cm, sp, msg, lvl, true) {
|
match emit(self, cm, sp, msg, None, lvl, true) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(e) => fail!("failed to print diagnostics: {}", e),
|
Err(e) => fail!("failed to print diagnostics: {}", e),
|
||||||
}
|
}
|
||||||
|
@ -347,7 +380,7 @@ impl Emitter for EmitterWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan,
|
fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan,
|
||||||
msg: &str, lvl: Level, custom: bool) -> io::IoResult<()> {
|
msg: &str, code: Option<&str>, lvl: Level, custom: bool) -> io::IoResult<()> {
|
||||||
let sp = rsp.span();
|
let sp = rsp.span();
|
||||||
let ss = cm.span_to_string(sp);
|
let ss = cm.span_to_string(sp);
|
||||||
let lines = cm.span_to_lines(sp);
|
let lines = cm.span_to_lines(sp);
|
||||||
|
@ -357,12 +390,12 @@ fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan,
|
||||||
// the span)
|
// the span)
|
||||||
let span_end = Span { lo: sp.hi, hi: sp.hi, expn_info: sp.expn_info};
|
let span_end = Span { lo: sp.hi, hi: sp.hi, expn_info: sp.expn_info};
|
||||||
let ses = cm.span_to_string(span_end);
|
let ses = cm.span_to_string(span_end);
|
||||||
try!(print_diagnostic(dst, ses.as_slice(), lvl, msg));
|
try!(print_diagnostic(dst, ses.as_slice(), lvl, msg, code));
|
||||||
if rsp.is_full_span() {
|
if rsp.is_full_span() {
|
||||||
try!(custom_highlight_lines(dst, cm, sp, lvl, lines));
|
try!(custom_highlight_lines(dst, cm, sp, lvl, lines));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try!(print_diagnostic(dst, ss.as_slice(), lvl, msg));
|
try!(print_diagnostic(dst, ss.as_slice(), lvl, msg, code));
|
||||||
if rsp.is_full_span() {
|
if rsp.is_full_span() {
|
||||||
try!(highlight_lines(dst, cm, sp, lvl, lines));
|
try!(highlight_lines(dst, cm, sp, lvl, lines));
|
||||||
}
|
}
|
||||||
|
@ -501,9 +534,9 @@ fn print_macro_backtrace(w: &mut EmitterWriter,
|
||||||
try!(print_diagnostic(w, ss.as_slice(), Note,
|
try!(print_diagnostic(w, ss.as_slice(), Note,
|
||||||
format!("in expansion of {}{}{}", pre,
|
format!("in expansion of {}{}{}", pre,
|
||||||
ei.callee.name,
|
ei.callee.name,
|
||||||
post).as_slice()));
|
post).as_slice(), None));
|
||||||
let ss = cm.span_to_string(ei.call_site);
|
let ss = cm.span_to_string(ei.call_site);
|
||||||
try!(print_diagnostic(w, ss.as_slice(), Note, "expansion site"));
|
try!(print_diagnostic(w, ss.as_slice(), Note, "expansion site", None));
|
||||||
try!(print_macro_backtrace(w, cm, ei.call_site));
|
try!(print_macro_backtrace(w, cm, ei.call_site));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
51
src/libsyntax/diagnostics/macros.rs
Normal file
51
src/libsyntax/diagnostics/macros.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![macro_escape]
|
||||||
|
|
||||||
|
// NOTE: remove after next snapshot
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! __register_diagnostic(
|
||||||
|
($code:tt, $description:tt) => ();
|
||||||
|
($code:tt) => ()
|
||||||
|
)
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! register_diagnostic(
|
||||||
|
($code:tt, $description:tt) => (__register_diagnostic!($code, $description));
|
||||||
|
($code:tt) => (__register_diagnostic!($code))
|
||||||
|
)
|
||||||
|
|
||||||
|
// NOTE: remove after next snapshot
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! __build_diagnostic_array(
|
||||||
|
($name:ident) => {
|
||||||
|
pub static $name: [(&'static str, &'static str), ..0] = [];
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// NOTE: remove after next snapshot
|
||||||
|
#[cfg(stage0)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! __diagnostic_used(
|
||||||
|
($code:ident) => {
|
||||||
|
()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! span_err(
|
||||||
|
($session:expr, $span:expr, $code:ident, $($arg:expr),*) => ({
|
||||||
|
__diagnostic_used!($code);
|
||||||
|
($session).span_err_with_code($span, format!($($arg),*).as_slice(), stringify!($code))
|
||||||
|
})
|
||||||
|
)
|
132
src/libsyntax/diagnostics/plugin.rs
Normal file
132
src/libsyntax/diagnostics/plugin.rs
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::gc::Gc;
|
||||||
|
use ast;
|
||||||
|
use ast::{Ident, Name, TokenTree};
|
||||||
|
use codemap::Span;
|
||||||
|
use ext::base::{ExtCtxt, MacExpr, MacItem, MacResult};
|
||||||
|
use ext::build::AstBuilder;
|
||||||
|
use parse::token;
|
||||||
|
|
||||||
|
local_data_key!(registered_diagnostics: RefCell<HashMap<Name, Option<Name>>>)
|
||||||
|
local_data_key!(used_diagnostics: RefCell<HashMap<Name, Span>>)
|
||||||
|
|
||||||
|
fn with_registered_diagnostics<T>(f: |&mut HashMap<Name, Option<Name>>| -> T) -> T {
|
||||||
|
match registered_diagnostics.get() {
|
||||||
|
Some(cell) => f(cell.borrow_mut().deref_mut()),
|
||||||
|
None => {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
let value = f(&mut map);
|
||||||
|
registered_diagnostics.replace(Some(RefCell::new(map)));
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_used_diagnostics<T>(f: |&mut HashMap<Name, Span>| -> T) -> T {
|
||||||
|
match used_diagnostics.get() {
|
||||||
|
Some(cell) => f(cell.borrow_mut().deref_mut()),
|
||||||
|
None => {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
let value = f(&mut map);
|
||||||
|
used_diagnostics.replace(Some(RefCell::new(map)));
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expand_diagnostic_used(ecx: &mut ExtCtxt, span: Span,
|
||||||
|
token_tree: &[TokenTree]) -> Box<MacResult> {
|
||||||
|
let code = match token_tree {
|
||||||
|
[ast::TTTok(_, token::IDENT(code, _))] => code,
|
||||||
|
_ => unreachable!()
|
||||||
|
};
|
||||||
|
with_registered_diagnostics(|diagnostics| {
|
||||||
|
if !diagnostics.contains_key(&code.name) {
|
||||||
|
ecx.span_err(span, format!(
|
||||||
|
"unknown diagnostic code {}", token::get_ident(code).get()
|
||||||
|
).as_slice());
|
||||||
|
}
|
||||||
|
()
|
||||||
|
});
|
||||||
|
with_used_diagnostics(|diagnostics| {
|
||||||
|
match diagnostics.swap(code.name, span) {
|
||||||
|
Some(previous_span) => {
|
||||||
|
ecx.span_warn(span, format!(
|
||||||
|
"diagnostic code {} already used", token::get_ident(code).get()
|
||||||
|
).as_slice());
|
||||||
|
ecx.span_note(previous_span, "previous invocation");
|
||||||
|
},
|
||||||
|
None => ()
|
||||||
|
}
|
||||||
|
()
|
||||||
|
});
|
||||||
|
MacExpr::new(quote_expr!(ecx, ()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expand_register_diagnostic(ecx: &mut ExtCtxt, span: Span,
|
||||||
|
token_tree: &[TokenTree]) -> Box<MacResult> {
|
||||||
|
let (code, description) = match token_tree {
|
||||||
|
[ast::TTTok(_, token::IDENT(ref code, _))] => {
|
||||||
|
(code, None)
|
||||||
|
},
|
||||||
|
[ast::TTTok(_, token::IDENT(ref code, _)),
|
||||||
|
ast::TTTok(_, token::COMMA),
|
||||||
|
ast::TTTok(_, token::LIT_STR_RAW(description, _))] => {
|
||||||
|
(code, Some(description))
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
};
|
||||||
|
with_registered_diagnostics(|diagnostics| {
|
||||||
|
if !diagnostics.insert(code.name, description) {
|
||||||
|
ecx.span_err(span, format!(
|
||||||
|
"diagnostic code {} already registered", token::get_ident(*code).get()
|
||||||
|
).as_slice());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let sym = Ident::new(token::gensym((
|
||||||
|
"__register_diagnostic_".to_string() + token::get_ident(*code).get()
|
||||||
|
).as_slice()));
|
||||||
|
MacItem::new(quote_item!(ecx, mod $sym {}).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expand_build_diagnostic_array(ecx: &mut ExtCtxt, span: Span,
|
||||||
|
token_tree: &[TokenTree]) -> Box<MacResult> {
|
||||||
|
let name = match token_tree {
|
||||||
|
[ast::TTTok(_, token::IDENT(ref name, _))] => name,
|
||||||
|
_ => unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (count, expr) = with_used_diagnostics(|diagnostics_in_use| {
|
||||||
|
with_registered_diagnostics(|diagnostics| {
|
||||||
|
let descriptions: Vec<Gc<ast::Expr>> = diagnostics
|
||||||
|
.iter().filter_map(|(code, description)| {
|
||||||
|
if !diagnostics_in_use.contains_key(code) {
|
||||||
|
ecx.span_warn(span, format!(
|
||||||
|
"diagnostic code {} never used", token::get_name(*code).get()
|
||||||
|
).as_slice());
|
||||||
|
}
|
||||||
|
description.map(|description| {
|
||||||
|
ecx.expr_tuple(span, vec![
|
||||||
|
ecx.expr_str(span, token::get_name(*code)),
|
||||||
|
ecx.expr_str(span, token::get_name(description))
|
||||||
|
])
|
||||||
|
})
|
||||||
|
}).collect();
|
||||||
|
(descriptions.len(), ecx.expr_vec(span, descriptions))
|
||||||
|
})
|
||||||
|
});
|
||||||
|
MacItem::new(quote_item!(ecx,
|
||||||
|
pub static $name: [(&'static str, &'static str), ..$count] = $expr;
|
||||||
|
).unwrap())
|
||||||
|
}
|
25
src/libsyntax/diagnostics/registry.rs
Normal file
25
src/libsyntax/diagnostics/registry.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub struct Registry {
|
||||||
|
descriptions: HashMap<&'static str, &'static str>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Registry {
|
||||||
|
pub fn new(descriptions: &[(&'static str, &'static str)]) -> Registry {
|
||||||
|
Registry { descriptions: descriptions.iter().map(|&tuple| tuple).collect() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_description(&self, code: &str) -> Option<&'static str> {
|
||||||
|
self.descriptions.find_equiv(&code).map(|desc| *desc)
|
||||||
|
}
|
||||||
|
}
|
|
@ -148,6 +148,8 @@ pub trait AstBuilder {
|
||||||
fn expr_some(&self, sp: Span, expr: Gc<ast::Expr>) -> Gc<ast::Expr>;
|
fn expr_some(&self, sp: Span, expr: Gc<ast::Expr>) -> Gc<ast::Expr>;
|
||||||
fn expr_none(&self, sp: Span) -> Gc<ast::Expr>;
|
fn expr_none(&self, sp: Span) -> Gc<ast::Expr>;
|
||||||
|
|
||||||
|
fn expr_tuple(&self, sp: Span, exprs: Vec<Gc<ast::Expr>>) -> Gc<ast::Expr>;
|
||||||
|
|
||||||
fn expr_fail(&self, span: Span, msg: InternedString) -> Gc<ast::Expr>;
|
fn expr_fail(&self, span: Span, msg: InternedString) -> Gc<ast::Expr>;
|
||||||
fn expr_unreachable(&self, span: Span) -> Gc<ast::Expr>;
|
fn expr_unreachable(&self, span: Span) -> Gc<ast::Expr>;
|
||||||
|
|
||||||
|
@ -674,6 +676,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||||
self.expr_path(none)
|
self.expr_path(none)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expr_tuple(&self, sp: Span, exprs: Vec<Gc<ast::Expr>>) -> Gc<ast::Expr> {
|
||||||
|
self.expr(sp, ast::ExprTup(exprs))
|
||||||
|
}
|
||||||
|
|
||||||
fn expr_fail(&self, span: Span, msg: InternedString) -> Gc<ast::Expr> {
|
fn expr_fail(&self, span: Span, msg: InternedString) -> Gc<ast::Expr> {
|
||||||
let loc = self.codemap().lookup_char_pos(span.lo);
|
let loc = self.codemap().lookup_char_pos(span.lo);
|
||||||
self.expr_call_global(
|
self.expr_call_global(
|
||||||
|
|
|
@ -58,7 +58,7 @@ pub fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> {
|
||||||
None => {
|
None => {
|
||||||
fld.cx.span_err(
|
fld.cx.span_err(
|
||||||
pth.span,
|
pth.span,
|
||||||
format!("macro undefined: '{}'",
|
format!("macro undefined: '{}!'",
|
||||||
extnamestr.get()).as_slice());
|
extnamestr.get()).as_slice());
|
||||||
|
|
||||||
// let compilation continue
|
// let compilation continue
|
||||||
|
@ -567,7 +567,7 @@ fn expand_stmt(s: &Stmt, fld: &mut MacroExpander) -> SmallVector<Gc<Stmt>> {
|
||||||
let marked_after = match fld.extsbox.find(&extname.name) {
|
let marked_after = match fld.extsbox.find(&extname.name) {
|
||||||
None => {
|
None => {
|
||||||
fld.cx.span_err(pth.span,
|
fld.cx.span_err(pth.span,
|
||||||
format!("macro undefined: '{}'",
|
format!("macro undefined: '{}!'",
|
||||||
extnamestr).as_slice());
|
extnamestr).as_slice());
|
||||||
return SmallVector::zero();
|
return SmallVector::zero();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,12 +27,11 @@
|
||||||
#![feature(quote, unsafe_destructor)]
|
#![feature(quote, unsafe_destructor)]
|
||||||
#![allow(deprecated)]
|
#![allow(deprecated)]
|
||||||
|
|
||||||
extern crate serialize;
|
|
||||||
extern crate term;
|
|
||||||
#[phase(plugin, link)] extern crate log;
|
|
||||||
|
|
||||||
extern crate fmt_macros;
|
extern crate fmt_macros;
|
||||||
extern crate debug;
|
extern crate debug;
|
||||||
|
#[phase(plugin, link)] extern crate log;
|
||||||
|
extern crate serialize;
|
||||||
|
extern crate term;
|
||||||
|
|
||||||
pub mod util {
|
pub mod util {
|
||||||
pub mod interner;
|
pub mod interner;
|
||||||
|
@ -41,26 +40,30 @@ pub mod util {
|
||||||
pub mod small_vector;
|
pub mod small_vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod diagnostics {
|
||||||
|
pub mod macros;
|
||||||
|
pub mod plugin;
|
||||||
|
pub mod registry;
|
||||||
|
}
|
||||||
|
|
||||||
pub mod syntax {
|
pub mod syntax {
|
||||||
pub use ext;
|
pub use ext;
|
||||||
pub use parse;
|
pub use parse;
|
||||||
pub use ast;
|
pub use ast;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod owned_slice;
|
|
||||||
pub mod attr;
|
|
||||||
pub mod diagnostic;
|
|
||||||
pub mod codemap;
|
|
||||||
pub mod abi;
|
pub mod abi;
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
pub mod ast_util;
|
|
||||||
pub mod ast_map;
|
pub mod ast_map;
|
||||||
pub mod visit;
|
pub mod ast_util;
|
||||||
pub mod fold;
|
pub mod attr;
|
||||||
|
pub mod codemap;
|
||||||
|
|
||||||
pub mod parse;
|
|
||||||
pub mod crateid;
|
pub mod crateid;
|
||||||
|
pub mod diagnostic;
|
||||||
|
pub mod fold;
|
||||||
|
pub mod owned_slice;
|
||||||
|
pub mod parse;
|
||||||
|
pub mod visit;
|
||||||
|
|
||||||
pub mod print {
|
pub mod print {
|
||||||
pub mod pp;
|
pub mod pp;
|
||||||
|
@ -70,31 +73,25 @@ pub mod print {
|
||||||
pub mod ext {
|
pub mod ext {
|
||||||
pub mod asm;
|
pub mod asm;
|
||||||
pub mod base;
|
pub mod base;
|
||||||
pub mod expand;
|
|
||||||
|
|
||||||
pub mod quote;
|
|
||||||
|
|
||||||
pub mod deriving;
|
|
||||||
|
|
||||||
pub mod build;
|
pub mod build;
|
||||||
|
pub mod bytes;
|
||||||
|
pub mod cfg;
|
||||||
|
pub mod concat;
|
||||||
|
pub mod concat_idents;
|
||||||
|
pub mod deriving;
|
||||||
|
pub mod env;
|
||||||
|
pub mod expand;
|
||||||
|
pub mod fmt;
|
||||||
|
pub mod format;
|
||||||
|
pub mod log_syntax;
|
||||||
|
pub mod mtwt;
|
||||||
|
pub mod quote;
|
||||||
|
pub mod source_util;
|
||||||
|
pub mod trace_macros;
|
||||||
|
|
||||||
pub mod tt {
|
pub mod tt {
|
||||||
pub mod transcribe;
|
pub mod transcribe;
|
||||||
pub mod macro_parser;
|
pub mod macro_parser;
|
||||||
pub mod macro_rules;
|
pub mod macro_rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod mtwt;
|
|
||||||
|
|
||||||
pub mod cfg;
|
|
||||||
pub mod fmt;
|
|
||||||
pub mod format;
|
|
||||||
pub mod env;
|
|
||||||
pub mod bytes;
|
|
||||||
pub mod concat;
|
|
||||||
pub mod concat_idents;
|
|
||||||
pub mod log_syntax;
|
|
||||||
pub mod source_util;
|
|
||||||
|
|
||||||
pub mod trace_macros;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1308,7 +1308,7 @@ mod test {
|
||||||
use std::io::util;
|
use std::io::util;
|
||||||
|
|
||||||
fn mk_sh() -> diagnostic::SpanHandler {
|
fn mk_sh() -> diagnostic::SpanHandler {
|
||||||
let emitter = diagnostic::EmitterWriter::new(box util::NullWriter);
|
let emitter = diagnostic::EmitterWriter::new(box util::NullWriter, None);
|
||||||
let handler = diagnostic::mk_handler(box emitter);
|
let handler = diagnostic::mk_handler(box emitter);
|
||||||
diagnostic::mk_span_handler(handler, CodeMap::new())
|
diagnostic::mk_span_handler(handler, CodeMap::new())
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ pub struct ParseSess {
|
||||||
|
|
||||||
pub fn new_parse_sess() -> ParseSess {
|
pub fn new_parse_sess() -> ParseSess {
|
||||||
ParseSess {
|
ParseSess {
|
||||||
span_diagnostic: mk_span_handler(default_handler(Auto), CodeMap::new()),
|
span_diagnostic: mk_span_handler(default_handler(Auto, None), CodeMap::new()),
|
||||||
included_mod_stack: RefCell::new(Vec::new()),
|
included_mod_stack: RefCell::new(Vec::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,5 +18,5 @@
|
||||||
extern crate macro_crate_test;
|
extern crate macro_crate_test;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
assert_eq!(3, unexported_macro!()); //~ ERROR macro undefined: 'unexported_macro'
|
assert_eq!(3, unexported_macro!()); //~ ERROR macro undefined: 'unexported_macro!'
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
print!(test!());
|
print!(test!());
|
||||||
//~^ ERROR: macro undefined: 'test'
|
//~^ ERROR: macro undefined: 'test!'
|
||||||
//~^^ ERROR: format argument must be a string literal
|
//~^^ ERROR: format argument must be a string literal
|
||||||
|
|
||||||
concat!(test!());
|
concat!(test!());
|
||||||
//~^ ERROR: macro undefined: 'test'
|
//~^ ERROR: macro undefined: 'test!'
|
||||||
}
|
}
|
||||||
|
|
28
src/test/compile-fail/rustc-diagnostics-1.rs
Normal file
28
src/test/compile-fail/rustc-diagnostics-1.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(rustc_diagnostic_macros)]
|
||||||
|
|
||||||
|
__register_diagnostic!(E0001)
|
||||||
|
__register_diagnostic!(E0003)
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
__diagnostic_used!(E0002);
|
||||||
|
//~^ ERROR unknown diagnostic code E0002
|
||||||
|
|
||||||
|
__diagnostic_used!(E0001);
|
||||||
|
//~^ NOTE previous invocation
|
||||||
|
|
||||||
|
__diagnostic_used!(E0001);
|
||||||
|
//~^ WARNING diagnostic code E0001 already used
|
||||||
|
}
|
||||||
|
|
||||||
|
__build_diagnostic_array!(DIAGNOSTICS)
|
||||||
|
//~^ WARN diagnostic code E0003 never used
|
20
src/test/compile-fail/rustc-diagnostics-2.rs
Normal file
20
src/test/compile-fail/rustc-diagnostics-2.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(rustc_diagnostic_macros)]
|
||||||
|
|
||||||
|
__register_diagnostic!(E0001)
|
||||||
|
__register_diagnostic!(E0001)
|
||||||
|
//~^ ERROR diagnostic code E0001 already registered
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
|
|
||||||
|
__build_diagnostic_array!(DIAGNOSTICS)
|
20
src/test/compile-fail/rustc-diagnostics-3.rs
Normal file
20
src/test/compile-fail/rustc-diagnostics-3.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
__register_diagnostic!(E0001)
|
||||||
|
//~^ ERROR macro undefined: '__register_diagnostic!'
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
__diagnostic_used!(E0001);
|
||||||
|
//~^ ERROR macro undefined: '__diagnostic_used!'
|
||||||
|
}
|
||||||
|
|
||||||
|
__build_diagnostic_array!(DIAGNOSTICS)
|
||||||
|
//~^ ERROR macro undefined: '__build_diagnostic_array!'
|
Loading…
Add table
Add a link
Reference in a new issue