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( "", "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),
|
||||
|
@ -807,6 +808,7 @@ mod test {
|
|||
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]
|
||||
|
@ -816,8 +818,9 @@ mod 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")));
|
||||
}
|
||||
|
@ -834,8 +837,9 @@ mod 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());
|
||||
|
|
|
@ -16,6 +16,7 @@ use driver::{PpmFlowGraph, PpmExpanded, PpmExpandedIdentified, PpmTyped};
|
|||
use driver::{PpmIdentified};
|
||||
use front;
|
||||
use lib::llvm::{ContextRef, ModuleRef};
|
||||
use lint;
|
||||
use metadata::common::LinkMeta;
|
||||
use metadata::creader;
|
||||
use middle::cfg;
|
||||
|
@ -26,7 +27,7 @@ use middle;
|
|||
use plugin::load::Plugins;
|
||||
use plugin::registry::Registry;
|
||||
use plugin;
|
||||
use lint;
|
||||
|
||||
use util::common::time;
|
||||
use util::ppaux;
|
||||
use util::nodemap::{NodeSet};
|
||||
|
@ -41,6 +42,7 @@ use std::io::MemReader;
|
|||
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};
|
||||
|
@ -213,6 +215,15 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ use std::task::TaskBuilder;
|
|||
use syntax::ast;
|
||||
use syntax::parse;
|
||||
use syntax::diagnostic::Emitter;
|
||||
use syntax::diagnostics;
|
||||
|
||||
use getopts;
|
||||
|
||||
|
@ -49,8 +50,24 @@ fn run_compiler(args: &[String]) {
|
|||
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 {
|
||||
|
@ -75,7 +92,7 @@ fn run_compiler(args: &[String]) {
|
|||
_ => 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));
|
||||
|
@ -383,14 +400,14 @@ fn parse_crate_attrs(sess: &Session, input: &Input) ->
|
|||
}
|
||||
|
||||
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,
|
||||
|
@ -429,7 +446,7 @@ fn monitor(f: proc():Send) {
|
|||
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.
|
||||
|
@ -437,6 +454,7 @@ fn monitor(f: proc():Send) {
|
|||
emitter.emit(
|
||||
None,
|
||||
"unexpected failure",
|
||||
None,
|
||||
diagnostic::Bug);
|
||||
}
|
||||
|
||||
|
@ -447,7 +465,7 @@ fn monitor(f: proc():Send) {
|
|||
"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() {
|
||||
|
@ -457,6 +475,7 @@ fn monitor(f: proc():Send) {
|
|||
format!("failed to read internal \
|
||||
stderr: {}",
|
||||
e).as_slice(),
|
||||
None,
|
||||
diagnostic::Error)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ use util::nodemap::NodeMap;
|
|||
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;
|
||||
|
@ -65,6 +66,9 @@ impl Session {
|
|||
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)
|
||||
}
|
||||
|
@ -197,11 +201,12 @@ impl Session {
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -66,6 +66,8 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
|
|||
|
||||
("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),
|
||||
|
@ -93,6 +95,7 @@ pub struct Features {
|
|||
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 {
|
||||
|
@ -101,6 +104,7 @@ 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.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"));
|
||||
}
|
||||
|
|
|
@ -32,6 +32,9 @@ This API is completely unstable and subject to change.
|
|||
#![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;
|
||||
|
@ -39,9 +42,11 @@ extern crate getopts;
|
|||
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;
|
||||
|
@ -127,6 +132,8 @@ pub mod lib {
|
|||
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.
|
||||
//
|
||||
|
|
|
@ -194,7 +194,7 @@ fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) {
|
|||
|
||||
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!()
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ impl Emitter for ExpectErrorEmitter {
|
|||
fn emit(&mut self,
|
||||
_cmsp: Option<(&codemap::CodeMap, Span)>,
|
||||
msg: &str,
|
||||
_: Option<&str>,
|
||||
lvl: Level)
|
||||
{
|
||||
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 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);
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ pub fn run(input: &str,
|
|||
|
||||
|
||||
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);
|
||||
|
||||
|
@ -150,7 +150,7 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool,
|
|||
};
|
||||
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();
|
||||
|
|
|
@ -12,6 +12,7 @@ extern crate libc;
|
|||
|
||||
use codemap::{Pos, Span};
|
||||
use codemap;
|
||||
use diagnostics;
|
||||
|
||||
use std::cell::{RefCell, Cell};
|
||||
use std::fmt;
|
||||
|
@ -59,7 +60,7 @@ pub enum ColorConfig {
|
|||
|
||||
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);
|
||||
}
|
||||
|
@ -90,6 +91,10 @@ impl SpanHandler {
|
|||
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);
|
||||
}
|
||||
|
@ -124,11 +129,11 @@ pub struct Handler {
|
|||
|
||||
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) {
|
||||
|
@ -153,13 +158,13 @@ impl Handler {
|
|||
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) -> ! {
|
||||
|
@ -169,7 +174,14 @@ impl Handler {
|
|||
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) {
|
||||
|
@ -184,8 +196,9 @@ pub fn mk_span_handler(handler: Handler, cm: codemap::CodeMap) -> SpanHandler {
|
|||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -262,8 +275,8 @@ fn print_maybe_styled(w: &mut EmitterWriter,
|
|||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
@ -272,13 +285,32 @@ fn print_diagnostic(dst: &mut EmitterWriter,
|
|||
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 {
|
||||
|
@ -287,7 +319,8 @@ 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 {
|
||||
|
@ -301,14 +334,15 @@ impl EmitterWriter {
|
|||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -324,11 +358,10 @@ impl Writer for Destination {
|
|||
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 {
|
||||
|
@ -339,7 +372,7 @@ impl Emitter for EmitterWriter {
|
|||
|
||||
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),
|
||||
}
|
||||
|
@ -347,7 +380,7 @@ impl Emitter for EmitterWriter {
|
|||
}
|
||||
|
||||
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);
|
||||
|
@ -357,12 +390,12 @@ fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan,
|
|||
// 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));
|
||||
}
|
||||
|
@ -501,9 +534,9 @@ fn print_macro_backtrace(w: &mut EmitterWriter,
|
|||
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(())
|
||||
|
|
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_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>;
|
||||
|
||||
|
@ -674,6 +676,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||
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(
|
||||
|
|
|
@ -58,7 +58,7 @@ pub fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> {
|
|||
None => {
|
||||
fld.cx.span_err(
|
||||
pth.span,
|
||||
format!("macro undefined: '{}'",
|
||||
format!("macro undefined: '{}!'",
|
||||
extnamestr.get()).as_slice());
|
||||
|
||||
// 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) {
|
||||
None => {
|
||||
fld.cx.span_err(pth.span,
|
||||
format!("macro undefined: '{}'",
|
||||
format!("macro undefined: '{}!'",
|
||||
extnamestr).as_slice());
|
||||
return SmallVector::zero();
|
||||
}
|
||||
|
|
|
@ -27,12 +27,11 @@
|
|||
#![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;
|
||||
|
@ -41,26 +40,30 @@ pub mod util {
|
|||
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 fold;
|
||||
|
||||
|
||||
pub mod parse;
|
||||
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 visit;
|
||||
|
||||
pub mod print {
|
||||
pub mod pp;
|
||||
|
@ -70,31 +73,25 @@ pub mod print {
|
|||
pub mod ext {
|
||||
pub mod asm;
|
||||
pub mod base;
|
||||
pub mod expand;
|
||||
|
||||
pub mod quote;
|
||||
|
||||
pub mod deriving;
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
|
|
@ -1308,7 +1308,7 @@ mod test {
|
|||
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())
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ pub struct ParseSess {
|
|||
|
||||
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()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,5 +18,5 @@
|
|||
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!'
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
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!'
|
||||
}
|
||||
|
|
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