--- /dev/null
+// 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.
+"##)
optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
optopt( "", "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
optflag("", "parse-only", "Parse only; do not compile, assemble, or link"),
+ optopt("", "explain", "Provide a detailed explanation of an error message", "OPT"),
optflagopt("", "pretty",
"Pretty-print the input instead of compiling;
valid types are: `normal` (un-annotated source),
use getopts::getopts;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
+ use syntax::diagnostics;
// When the user supplies --test we should implicitly supply --cfg test
#[test]
Ok(m) => m,
Err(f) => fail!("test_switch_implies_cfg_test: {}", f)
};
+ let registry = diagnostics::registry::Registry::new([]);
let sessopts = build_session_options(matches);
- let sess = build_session(sessopts, None);
+ let sess = build_session(sessopts, None, registry);
let cfg = build_configuration(&sess);
assert!((attr::contains_name(cfg.as_slice(), "test")));
}
fail!("test_switch_implies_cfg_test_unless_cfg_test: {}", f)
}
};
+ let registry = diagnostics::registry::Registry::new([]);
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 mut test_items = cfg.iter().filter(|m| m.name().equiv(&("test")));
assert!(test_items.next().is_some());
use driver::{PpmIdentified};
use front;
use lib::llvm::{ContextRef, ModuleRef};
+use lint;
use metadata::common::LinkMeta;
use metadata::creader;
use middle::cfg;
use plugin::load::Plugins;
use plugin::registry::Registry;
use plugin;
-use lint;
+
use util::common::time;
use util::ppaux;
use util::nodemap::{NodeSet};
use syntax::ast;
use syntax::attr;
use syntax::attr::{AttrMetaMethods};
+use syntax::diagnostics;
use syntax::parse;
use syntax::parse::token;
use syntax::print::{pp, pprust};
let mut registry = Registry::new(&krate);
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() {
registrar(&mut registry);
}
use syntax::ast;
use syntax::parse;
use syntax::diagnostic::Emitter;
+use syntax::diagnostics;
use getopts;
Some(matches) => matches,
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() {
0u => {
if sopts.describe_lints {
_ => 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 odir = matches.opt_str("out-dir").map(|o| Path::new(o));
let ofile = matches.opt_str("o").map(|o| Path::new(o));
}
pub fn early_error(msg: &str) -> ! {
- let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto);
- emitter.emit(None, msg, diagnostic::Fatal);
+ let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None);
+ emitter.emit(None, msg, None, diagnostic::Fatal);
fail!(diagnostic::FatalError);
}
pub fn early_warn(msg: &str) {
- let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto);
- emitter.emit(None, msg, diagnostic::Warning);
+ let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None);
+ emitter.emit(None, msg, None, diagnostic::Warning);
}
pub fn list_metadata(sess: &Session, path: &Path,
Err(value) => {
// Task failed without emitting a fatal diagnostic
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
// it wants to print.
emitter.emit(
None,
"unexpected failure",
+ None,
diagnostic::Bug);
}
"run with `RUST_BACKTRACE=1` for a backtrace".to_string(),
];
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() {
format!("failed to read internal \
stderr: {}",
e).as_slice(),
+ None,
diagnostic::Error)
}
}
use syntax::ast::NodeId;
use syntax::codemap::Span;
use syntax::diagnostic;
+use syntax::diagnostics;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::ParseSess;
pub fn span_err(&self, sp: Span, msg: &str) {
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) {
self.diagnostic().handler().err(msg)
}
}
pub fn build_session(sopts: config::Options,
- local_crate_source_file: Option<Path>)
+ local_crate_source_file: Option<Path>,
+ registry: diagnostics::registry::Registry)
-> Session {
let codemap = codemap::CodeMap::new();
let diagnostic_handler =
- diagnostic::default_handler(sopts.color);
+ diagnostic::default_handler(sopts.color, Some(registry));
let span_diagnostic_handler =
diagnostic::mk_span_handler(diagnostic_handler, codemap);
("quad_precision_float", Removed),
+ ("rustc_diagnostic_macros", Active),
+
// A temporary feature gate used to enable parser extensions needed
// to bootstrap fix for #5723.
("issue_5723_bootstrap", Active),
pub default_type_params: Cell<bool>,
pub issue_5723_bootstrap: Cell<bool>,
pub overloaded_calls: Cell<bool>,
+ pub rustc_diagnostic_macros: Cell<bool>
}
impl Features {
default_type_params: Cell::new(false),
issue_5723_bootstrap: Cell::new(false),
overloaded_calls: Cell::new(false),
+ rustc_diagnostic_macros: Cell::new(false)
}
}
}
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.overloaded_calls.set(cx.has_feature("overloaded_calls"));
+ sess.features.rustc_diagnostic_macros.set(cx.has_feature("rustc_diagnostic_macros"));
}
#![feature(macro_rules, globs, struct_variant, managed_boxes, quote)]
#![feature(default_type_params, phase, unsafe_destructor)]
+#![allow(unknown_features)] // NOTE: Remove after next snapshot
+#![feature(rustc_diagnostic_macros)]
+
extern crate arena;
extern crate debug;
extern crate flate;
extern crate graphviz;
extern crate libc;
extern crate serialize;
-extern crate syntax;
extern crate time;
#[phase(plugin, link)] extern crate log;
+#[phase(plugin, link)] extern crate syntax;
+
+mod diagnostics;
pub mod middle {
pub mod def;
pub mod llvmdeps;
}
+__build_diagnostic_array!(DIAGNOSTICS)
+
// A private module so that macro-expanded idents like
// `::rustc::lint::Lint` will also work in `rustc` itself.
//
let v = vec!(*pat);
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 => (),
UsefulWithWitness(_) => unreachable!()
}
fn emit(&mut self,
_cmsp: Option<(&codemap::CodeMap, Span)>,
msg: &str,
+ _: Option<&str>,
lvl: Level)
{
remove_message(self, msg, lvl);
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 =
syntax::diagnostic::mk_span_handler(diagnostic_handler, codemap);
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 =
diagnostic::mk_span_handler(diagnostic_handler, codemap);
};
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
let codemap = CodeMap::new();
use codemap::{Pos, Span};
use codemap;
+use diagnostics;
use std::cell::{RefCell, Cell};
use std::fmt;
pub trait Emitter {
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,
sp: RenderSpan, msg: &str, lvl: Level);
}
self.handler.emit(Some((&self.cm, sp)), msg, Error);
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) {
self.handler.emit(Some((&self.cm, sp)), msg, Warning);
}
impl Handler {
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);
}
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();
}
pub fn bump_err_count(&self) {
self.fatal(s.as_slice());
}
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) {
- self.emit.borrow_mut().emit(None, msg, Note);
+ self.emit.borrow_mut().emit(None, msg, None, Note);
}
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);
}
pub fn unimpl(&self, msg: &str) -> ! {
cmsp: Option<(&codemap::CodeMap, Span)>,
msg: &str,
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,
sp: RenderSpan, msg: &str, lvl: Level) {
}
}
-pub fn default_handler(color_config: ColorConfig) -> Handler {
- mk_handler(box EmitterWriter::stderr(color_config))
+pub fn default_handler(color_config: ColorConfig,
+ registry: Option<diagnostics::registry::Registry>) -> Handler {
+ mk_handler(box EmitterWriter::stderr(color_config, registry))
}
pub fn mk_handler(e: Box<Emitter + Send>) -> Handler {
}
}
-fn print_diagnostic(dst: &mut EmitterWriter,
- topic: &str, lvl: Level, msg: &str) -> io::IoResult<()> {
+fn print_diagnostic(dst: &mut EmitterWriter, topic: &str, lvl: Level,
+ msg: &str, code: Option<&str>) -> io::IoResult<()> {
if !topic.is_empty() {
try!(write!(&mut dst.dst, "{} ", topic));
}
format!("{}: ", lvl.to_string()).as_slice(),
term::attr::ForegroundColor(lvl.color())));
try!(print_maybe_styled(dst,
- format!("{}\n", msg).as_slice(),
+ format!("{}", msg).as_slice(),
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(())
}
pub struct EmitterWriter {
dst: Destination,
+ registry: Option<diagnostics::registry::Registry>
}
enum Destination {
}
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 use_color = match color_config {
Some(t) => Terminal(t),
None => Raw(box stderr),
};
- EmitterWriter { dst: dst }
+ EmitterWriter { dst: dst, registry: registry }
} else {
- EmitterWriter { dst: Raw(box stderr) }
+ EmitterWriter { dst: Raw(box stderr), registry: registry }
}
}
- pub fn new(dst: Box<Writer + Send>) -> EmitterWriter {
- EmitterWriter { dst: Raw(dst) }
+ pub fn new(dst: Box<Writer + Send>,
+ registry: Option<diagnostics::registry::Registry>) -> EmitterWriter {
+ EmitterWriter { dst: Raw(dst), registry: registry }
}
}
impl Emitter for EmitterWriter {
fn emit(&mut self,
cmsp: Option<(&codemap::CodeMap, Span)>,
- msg: &str,
- lvl: Level) {
+ msg: &str, code: Option<&str>, lvl: Level) {
let error = match cmsp {
- Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, lvl, false),
- None => print_diagnostic(self, "", lvl, msg),
+ Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, code, lvl, false),
+ None => print_diagnostic(self, "", lvl, msg, code),
};
match error {
fn custom_emit(&mut self, cm: &codemap::CodeMap,
sp: RenderSpan, msg: &str, lvl: Level) {
- match emit(self, cm, sp, msg, lvl, true) {
+ match emit(self, cm, sp, msg, None, lvl, true) {
Ok(()) => {}
Err(e) => fail!("failed to print diagnostics: {}", e),
}
}
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 ss = cm.span_to_string(sp);
let lines = cm.span_to_lines(sp);
// the span)
let span_end = Span { lo: sp.hi, hi: sp.hi, expn_info: sp.expn_info};
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() {
try!(custom_highlight_lines(dst, cm, sp, lvl, lines));
}
} 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() {
try!(highlight_lines(dst, cm, sp, lvl, lines));
}
try!(print_diagnostic(w, ss.as_slice(), Note,
format!("in expansion of {}{}{}", pre,
ei.callee.name,
- post).as_slice()));
+ post).as_slice(), None));
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));
}
Ok(())
--- /dev/null
+// 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))
+ })
+)
--- /dev/null
+// 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())
+}
--- /dev/null
+// 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)
+ }
+}
fn expr_some(&self, sp: Span, expr: Gc<ast::Expr>) -> 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_unreachable(&self, span: Span) -> Gc<ast::Expr>;
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> {
let loc = self.codemap().lookup_char_pos(span.lo);
self.expr_call_global(
None => {
fld.cx.span_err(
pth.span,
- format!("macro undefined: '{}'",
+ format!("macro undefined: '{}!'",
extnamestr.get()).as_slice());
// let compilation continue
let marked_after = match fld.extsbox.find(&extname.name) {
None => {
fld.cx.span_err(pth.span,
- format!("macro undefined: '{}'",
+ format!("macro undefined: '{}!'",
extnamestr).as_slice());
return SmallVector::zero();
}
#![feature(quote, unsafe_destructor)]
#![allow(deprecated)]
-extern crate serialize;
-extern crate term;
-#[phase(plugin, link)] extern crate log;
-
extern crate fmt_macros;
extern crate debug;
+#[phase(plugin, link)] extern crate log;
+extern crate serialize;
+extern crate term;
pub mod util {
pub mod interner;
pub mod small_vector;
}
+pub mod diagnostics {
+ pub mod macros;
+ pub mod plugin;
+ pub mod registry;
+}
+
pub mod syntax {
pub use ext;
pub use parse;
pub use ast;
}
-pub mod owned_slice;
-pub mod attr;
-pub mod diagnostic;
-pub mod codemap;
pub mod abi;
pub mod ast;
-pub mod ast_util;
pub mod ast_map;
-pub mod visit;
+pub mod ast_util;
+pub mod attr;
+pub mod codemap;
+pub mod crateid;
+pub mod diagnostic;
pub mod fold;
-
-
+pub mod owned_slice;
pub mod parse;
-pub mod crateid;
+pub mod visit;
pub mod print {
pub mod pp;
pub mod ext {
pub mod asm;
pub mod base;
+ 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 deriving;
-
- pub mod build;
+ pub mod source_util;
+ pub mod trace_macros;
pub mod tt {
pub mod transcribe;
pub mod macro_parser;
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;
}
use std::io::util;
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);
diagnostic::mk_span_handler(handler, CodeMap::new())
}
pub fn new_parse_sess() -> 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()),
}
}
extern crate macro_crate_test;
fn main() {
- assert_eq!(3, unexported_macro!()); //~ ERROR macro undefined: 'unexported_macro'
+ assert_eq!(3, unexported_macro!()); //~ ERROR macro undefined: 'unexported_macro!'
}
fn main() {
print!(test!());
- //~^ ERROR: macro undefined: 'test'
+ //~^ ERROR: macro undefined: 'test!'
//~^^ ERROR: format argument must be a string literal
concat!(test!());
- //~^ ERROR: macro undefined: 'test'
+ //~^ ERROR: macro undefined: 'test!'
}
--- /dev/null
+// 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
--- /dev/null
+// 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)
--- /dev/null
+// 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!'