Skip to content

Commit

Permalink
auto merge of rust-lang#15336 : jakub-/rust/diagnostics, r=brson
Browse files Browse the repository at this point in the history
This is a continuation of @brson's work from rust-lang#12144.

This implements the minimal scaffolding that allows mapping diagnostic messages to alpha-numeric codes, which could improve the searchability of errors. In addition, there's a new compiler option, `--explain {code}` which takes an error code and prints out a somewhat detailed explanation of the error. Example:

```rust
fn f(x: Option<bool>) {
	match x {
		Some(true) | Some(false) => (),
		None => (),
		Some(true) => ()
	}
}
```

```shell
[~/rust]$ ./build/x86_64-apple-darwin/stage2/bin/rustc ./diagnostics.rs --crate-type dylib
diagnostics.rs:5:3: 5:13 error: unreachable pattern [E0001] (pass `--explain E0001` to see a detailed explanation)
diagnostics.rs:5 		Some(true) => ()
                 		^~~~~~~~~~
error: aborting due to previous error
[~/rust]$ ./build/x86_64-apple-darwin/stage2/bin/rustc --explain E0001

    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.

```

I've refrained from migrating many errors to actually use the new macros as it can be done in an incremental fashion but if we're happy with the approach, it'd be good to do all of them sooner rather than later.

Originally, I was going to make libdiagnostics a separate crate but that's posing some interesting challenges with semi-circular dependencies. In particular, librustc would have a plugin-phase dependency on libdiagnostics, which itself depends on librustc. Per my conversation with @alexcrichton, it seems like the snapshotting process would also have to change. So for now the relevant modules from libdiagnostics are included using `#[path = ...] mod`.
  • Loading branch information
bors committed Jul 10, 2014
2 parents a672456 + 9b9cce2 commit 0e80dbe
Show file tree
Hide file tree
Showing 25 changed files with 466 additions and 84 deletions.
18 changes: 18 additions & 0 deletions src/librustc/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -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.
"##)
8 changes: 6 additions & 2 deletions src/librustc/driver/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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]
Expand All @@ -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")));
}
Expand All @@ -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());
Expand Down
13 changes: 12 additions & 1 deletion src/librustc/driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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};
Expand All @@ -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};
Expand Down Expand Up @@ -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 &registrar in registrars.iter() {
registrar(&mut registry);
}
Expand Down
35 changes: 27 additions & 8 deletions src/librustc/driver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use std::task::TaskBuilder;
use syntax::ast;
use syntax::parse;
use syntax::diagnostic::Emitter;
use syntax::diagnostics;

use getopts;

Expand All @@ -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 {
Expand All @@ -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));
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -429,14 +446,15 @@ 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.
if !value.is::<diagnostic::ExplicitBug>() {
emitter.emit(
None,
"unexpected failure",
None,
diagnostic::Bug);
}

Expand All @@ -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() {
Expand All @@ -457,6 +475,7 @@ fn monitor(f: proc():Send) {
format!("failed to read internal \
stderr: {}",
e).as_slice(),
None,
diagnostic::Error)
}
}
Expand Down
9 changes: 7 additions & 2 deletions src/librustc/driver/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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);

Expand Down
5 changes: 5 additions & 0 deletions src/librustc/front/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
}
}
}
Expand Down Expand Up @@ -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"));
}
9 changes: 8 additions & 1 deletion src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,21 @@ 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;
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;
Expand Down Expand Up @@ -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.
//
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!()
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/typeck/infer/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
4 changes: 2 additions & 2 deletions src/librustdoc/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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();
Expand Down
Loading

0 comments on commit 0e80dbe

Please sign in to comment.