rollup merge of #21289: brson/errorcodes

This does the bare minimum to make registration of error codes work again. After this patch, every call to `span_err!` with an error code gets that error code validated against a list in that crate and a new tidy script `errorck.py` validates that no error codes are duplicated globally.

There are further improvements to be made yet, detailed in #19624.

r? @nikomatsakis
This commit is contained in:
Alex Crichton 2015-01-21 09:13:46 -08:00
commit b250d9a3c8
38 changed files with 618 additions and 476 deletions

View File

@ -300,6 +300,7 @@ tidy:
| grep '^$(S)src/libbacktrace' -v \ | grep '^$(S)src/libbacktrace' -v \
| grep '^$(S)src/rust-installer' -v \ | grep '^$(S)src/rust-installer' -v \
| xargs $(CFG_PYTHON) $(S)src/etc/check-binaries.py | xargs $(CFG_PYTHON) $(S)src/etc/check-binaries.py
$(Q) $(CFG_PYTHON) $(S)src/etc/errorck.py $(S)src/
endif endif

70
src/etc/errorck.py Normal file
View File

@ -0,0 +1,70 @@
# Copyright 2015 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.
# Digs error codes out of files named 'diagnostics.rs' across
# the tree, and ensures thare are no duplicates.
import sys, os, re
src_dir = sys.argv[1]
errcode_map = { }
for (dirpath, dirnames, filenames) in os.walk(src_dir):
if "src/test" in dirpath or "src/llvm" in dirpath:
# Short circuit for fast
continue
for filename in filenames:
if filename != "diagnostics.rs":
continue
path = os.path.join(dirpath, filename)
line_num = 1
with open(path, 'r') as f:
for line in f:
p = re.compile("(E\d\d\d\d)")
m = p.search(line)
if not m is None:
errcode = m.group(1)
new_record = [(errcode, path, line_num, line)]
existing = errcode_map.get(errcode)
if existing is not None:
# This is a dupe
errcode_map[errcode] = existing + new_record
else:
errcode_map[errcode] = new_record
line_num += 1
errors = False
all_errors = []
for errcode in errcode_map:
entries = errcode_map[errcode]
all_errors += [entries[0][0]]
if len(entries) > 1:
print "error: duplicate error code " + errcode
for entry in entries:
print entry[1] + ": " + str(entry[2])
print entry[3]
errors = True
print str(len(errcode_map)) + " error codes"
all_errors.sort()
all_errors.reverse()
print "highest error code: " + all_errors[0]
if errors:
sys.exit(1)

View File

@ -10,28 +10,55 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
register_diagnostic! { E0001, r##" register_long_diagnostics! {
E0001: r##"
This error suggests that the expression arm corresponding to the noted pattern 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, will never be reached as for all possible values of the expression being matched,
one of the preceeding patterns will match. one of the preceeding patterns will match.
This means that perhaps some of the preceeding patterns are too general, this This means that perhaps some of the preceeding patterns are too general, this
one is too specific or the ordering is incorrect. one is too specific or the ordering is incorrect.
"## } "##,
E0003: r##"
Not-a-Number (NaN) values can not be compared for equality and hence can never match
the input to a match expression. To match against NaN values, you should instead use
the `is_nan` method in a guard, as in: x if x.is_nan() => ...
"##,
E0004: r##"
This error indicates that the compiler can not guarantee a matching pattern for one
or more possible inputs to a match expression. Guaranteed matches are required in order
to assign values to match expressions, or alternatively, determine the flow of execution.
If you encounter this error you must alter your patterns so that every possible value of
the input type is matched. For types with a small number of variants (like enums) you
should probably cover all cases explicitly. Alternatively, the underscore `_` wildcard
pattern can be added after all other patterns to match "anything else".
"##,
// FIXME: Remove duplication here?
E0005: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee that a
name will be extracted in all cases. If you encounter this error you probably need
to use a `match` or `if let` to deal with the possibility of failure.
"##,
E0006: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee that a
name will be extracted in all cases. If you encounter this error you probably need
to use a `match` or `if let` to deal with the possibility of failure.
"##
}
register_diagnostics! { register_diagnostics! {
E0002, E0002,
E0003,
E0004,
E0005,
E0006,
E0007, E0007,
E0008, E0008,
E0009, E0009,
E0010, E0010,
E0011, E0011,
E0012, E0012,
E0013,
E0014, E0014,
E0015, E0015,
E0016, E0016,
@ -49,24 +76,58 @@ register_diagnostics! {
E0137, E0137,
E0138, E0138,
E0139, E0139,
E0140,
E0152, E0152,
E0153,
E0157,
E0158, E0158,
E0161, E0161,
E0162, E0162,
E0165, E0165,
E0166,
E0167,
E0168,
E0169,
E0170, E0170,
E0171, E0261, // use of undeclared lifetime name
E0172, E0262, // illegal lifetime parameter name
E0173, E0263, // lifetime name declared twice in same scope
E0174, E0264, // unknown external lang item
E0177, E0265, // recursive constant
E0178, E0266, // expected item
E0179 E0267, // thing inside of a closure
E0268, // thing outside of a loop
E0269, // not all control paths return a value
E0270, // computation may converge in a function marked as diverging
E0271, // type mismatch resolving
E0272, // rustc_on_unimplemented attribute refers to non-existent type parameter
E0273, // rustc_on_unimplemented must have named format arguments
E0274, // rustc_on_unimplemented must have a value
E0275, // overflow evaluating requirement
E0276, // requirement appears on impl method but not on corresponding trait method
E0277, // trait is not implemented for type
E0278, // requirement is not satisfied
E0279, // requirement is not satisfied
E0280, // requirement is not satisfied
E0281, // type implements trait but other trait is required
E0282, // unable to infer enough type information about
E0283, // cannot resolve type
E0284, // cannot resolve type
E0285, // overflow evaluation builtin bounds
E0296, // malformed recursion limit attribute
E0297, // refutable pattern in for loop binding
E0298, // mismatched types between arms
E0299, // mismatched types between arms
E0300, // unexpanded macro
E0301, // cannot mutable borrow in a pattern guard
E0302, // cannot assign in a pattern guard
E0303, // pattern bindings are not allowed after an `@`
E0304, // expected signed integer constant
E0305, // expected constant
E0306, // expected positive integer for repeat count
E0307, // expected constant integer for repeat count
E0308,
E0309, // thing may not live long enough
E0310, // thing may not live long enough
E0311, // thing may not live long enough
E0312, // lifetime of reference outlives lifetime of borrowed content
E0313, // lifetime of borrowed pointer outlives lifetime of captured variable
E0314, // closure outlives stack frame
E0315 // cannot invoke closure outside of its lifetime
} }
__build_diagnostic_array! { DIAGNOSTICS }

View File

@ -54,7 +54,9 @@ extern crate test;
pub use rustc_llvm as llvm; pub use rustc_llvm as llvm;
mod diagnostics; // NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;
pub mod back { pub mod back {
pub use rustc_back::abi; pub use rustc_back::abi;
@ -132,8 +134,6 @@ pub mod lib {
pub use llvm; pub use llvm;
} }
__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.
// //

View File

@ -73,12 +73,12 @@ impl<'a> CheckLoopVisitor<'a> {
match self.cx { match self.cx {
Loop => {} Loop => {}
Closure => { Closure => {
self.sess.span_err(span, span_err!(self.sess, span, E0267,
&format!("`{}` inside of a closure", name)[]); "`{}` inside of a closure", name);
} }
Normal => { Normal => {
self.sess.span_err(span, span_err!(self.sess, span, E0268,
&format!("`{}` outside of loop", name)[]); "`{}` outside of loop", name);
} }
} }
} }

View File

@ -226,11 +226,10 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &ast::Expr) {
ast::ExprForLoop(ref pat, _, _, _) => { ast::ExprForLoop(ref pat, _, _, _) => {
let mut static_inliner = StaticInliner::new(cx.tcx); let mut static_inliner = StaticInliner::new(cx.tcx);
is_refutable(cx, &*static_inliner.fold_pat((*pat).clone()), |uncovered_pat| { is_refutable(cx, &*static_inliner.fold_pat((*pat).clone()), |uncovered_pat| {
cx.tcx.sess.span_err( span_err!(cx.tcx.sess, pat.span, E0297,
pat.span, "refutable pattern in `for` loop binding: \
&format!("refutable pattern in `for` loop binding: \
`{}` not covered", `{}` not covered",
pat_to_string(uncovered_pat))[]); pat_to_string(uncovered_pat));
}); });
// Check legality of move bindings. // Check legality of move bindings.
@ -869,7 +868,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
Some(true) => Some(vec![]), Some(true) => Some(vec![]),
Some(false) => None, Some(false) => None,
None => { None => {
cx.tcx.sess.span_err(pat_span, "mismatched types between arms"); span_err!(cx.tcx.sess, pat_span, E0298, "mismatched types between arms");
None None
} }
} }
@ -882,7 +881,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
Some(true) => Some(vec![]), Some(true) => Some(vec![]),
Some(false) => None, Some(false) => None,
None => { None => {
cx.tcx.sess.span_err(pat_span, "mismatched types between arms"); span_err!(cx.tcx.sess, pat_span, E0299, "mismatched types between arms");
None None
} }
} }
@ -921,7 +920,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
} }
ast::PatMac(_) => { ast::PatMac(_) => {
cx.tcx.sess.span_err(pat_span, "unexpanded macro"); span_err!(cx.tcx.sess, pat_span, E0300, "unexpanded macro");
None None
} }
}; };
@ -1082,11 +1081,8 @@ impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> {
_: LoanCause) { _: LoanCause) {
match kind { match kind {
MutBorrow => { MutBorrow => {
self.cx span_err!(self.cx.tcx.sess, span, E0301,
.tcx "cannot mutably borrow in a pattern guard")
.sess
.span_err(span,
"cannot mutably borrow in a pattern guard")
} }
ImmBorrow | UniqueImmBorrow => {} ImmBorrow | UniqueImmBorrow => {}
} }
@ -1095,10 +1091,7 @@ impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> {
fn mutate(&mut self, _: NodeId, span: Span, _: cmt, mode: MutateMode) { fn mutate(&mut self, _: NodeId, span: Span, _: cmt, mode: MutateMode) {
match mode { match mode {
JustWrite | WriteAndRead => { JustWrite | WriteAndRead => {
self.cx span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard")
.tcx
.sess
.span_err(span, "cannot assign in a pattern guard")
} }
Init => {} Init => {}
} }
@ -1120,7 +1113,7 @@ struct AtBindingPatternVisitor<'a, 'b:'a, 'tcx:'b> {
impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> { impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> {
fn visit_pat(&mut self, pat: &Pat) { fn visit_pat(&mut self, pat: &Pat) {
if !self.bindings_allowed && pat_is_binding(&self.cx.tcx.def_map, pat) { if !self.bindings_allowed && pat_is_binding(&self.cx.tcx.def_map, pat) {
self.cx.tcx.sess.span_err(pat.span, span_err!(self.cx.tcx.sess, pat.span, E0303,
"pattern bindings are not allowed \ "pattern bindings are not allowed \
after an `@`"); after an `@`");
} }

View File

@ -83,7 +83,7 @@ pub fn check_item_recursion<'a>(sess: &'a Session,
impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> { impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> {
fn visit_item(&mut self, it: &ast::Item) { fn visit_item(&mut self, it: &ast::Item) {
if self.idstack.iter().any(|x| x == &(it.id)) { if self.idstack.iter().any(|x| x == &(it.id)) {
self.sess.span_err(self.root_it.span, "recursive constant"); span_err!(self.sess, self.root_it.span, E0265, "recursive constant");
return; return;
} }
self.idstack.push(it.id); self.idstack.push(it.id);
@ -103,9 +103,9 @@ impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> {
self.visit_item(item), self.visit_item(item),
ast_map::NodeForeignItem(_) => {}, ast_map::NodeForeignItem(_) => {},
_ => { _ => {
self.sess.span_err(e.span, span_err!(self.sess, e.span, E0266,
&format!("expected item, found {}", "expected item, found {}",
self.ast_map.node_to_string(def_id.node))[]); self.ast_map.node_to_string(def_id.node));
return; return;
}, },
} }

View File

@ -371,12 +371,11 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
infer::EquatePredicate(_) => "equality predicate not satisfied", infer::EquatePredicate(_) => "equality predicate not satisfied",
}; };
self.tcx.sess.span_err( span_err!(self.tcx.sess, trace.origin.span(), E0308,
trace.origin.span(), "{}: {} ({})",
&format!("{}: {} ({})",
message_root_str, message_root_str,
expected_found_str, expected_found_str,
ty::type_err_to_str(self.tcx, terr))[]); ty::type_err_to_str(self.tcx, terr));
match trace.origin { match trace.origin {
infer::MatchExpressionArm(_, arm_span) => infer::MatchExpressionArm(_, arm_span) =>
@ -443,9 +442,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
match sub { match sub {
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
// Does the required lifetime have a nice name we can print? // Does the required lifetime have a nice name we can print?
self.tcx.sess.span_err( span_err!(self.tcx.sess, origin.span(), E0309,
origin.span(), "{} may not live long enough", labeled_user_string);
&format!("{} may not live long enough", labeled_user_string)[]);
self.tcx.sess.span_help( self.tcx.sess.span_help(
origin.span(), origin.span(),
&format!( &format!(
@ -456,9 +454,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
ty::ReStatic => { ty::ReStatic => {
// Does the required lifetime have a nice name we can print? // Does the required lifetime have a nice name we can print?
self.tcx.sess.span_err( span_err!(self.tcx.sess, origin.span(), E0310,
origin.span(), "{} may not live long enough", labeled_user_string);
&format!("{} may not live long enough", labeled_user_string)[]);
self.tcx.sess.span_help( self.tcx.sess.span_help(
origin.span(), origin.span(),
&format!( &format!(
@ -468,11 +465,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
_ => { _ => {
// If not, be less specific. // If not, be less specific.
self.tcx.sess.span_err( span_err!(self.tcx.sess, origin.span(), E0311,
origin.span(),
&format!(
"{} may not live long enough", "{} may not live long enough",
labeled_user_string)[]); labeled_user_string);
self.tcx.sess.span_help( self.tcx.sess.span_help(
origin.span(), origin.span(),
&format!( &format!(
@ -499,8 +494,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
self.report_and_explain_type_error(trace, &terr); self.report_and_explain_type_error(trace, &terr);
} }
infer::Reborrow(span) => { infer::Reborrow(span) => {
self.tcx.sess.span_err( span_err!(self.tcx.sess, span, E0312,
span,
"lifetime of reference outlines \ "lifetime of reference outlines \
lifetime of borrowed content..."); lifetime of borrowed content...");
note_and_explain_region( note_and_explain_region(
@ -515,14 +509,13 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
""); "");
} }
infer::ReborrowUpvar(span, ref upvar_id) => { infer::ReborrowUpvar(span, ref upvar_id) => {
self.tcx.sess.span_err( span_err!(self.tcx.sess, span, E0313,
span, "lifetime of borrowed pointer outlives \
&format!("lifetime of borrowed pointer outlives \
lifetime of captured variable `{}`...", lifetime of captured variable `{}`...",
ty::local_var_name_str(self.tcx, ty::local_var_name_str(self.tcx,
upvar_id.var_id) upvar_id.var_id)
.get() .get()
.to_string())[]); .to_string());
note_and_explain_region( note_and_explain_region(
self.tcx, self.tcx,
"...the borrowed pointer is valid for ", "...the borrowed pointer is valid for ",
@ -539,8 +532,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
""); "");
} }
infer::InfStackClosure(span) => { infer::InfStackClosure(span) => {
self.tcx.sess.span_err( span_err!(self.tcx.sess, span, E0314,
span,
"closure outlives stack frame"); "closure outlives stack frame");
note_and_explain_region( note_and_explain_region(
self.tcx, self.tcx,
@ -554,8 +546,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
""); "");
} }
infer::InvokeClosure(span) => { infer::InvokeClosure(span) => {
self.tcx.sess.span_err( span_err!(self.tcx.sess, span, E0315,
span,
"cannot invoke closure outside of its lifetime"); "cannot invoke closure outside of its lifetime");
note_and_explain_region( note_and_explain_region(
self.tcx, self.tcx,

View File

@ -1557,8 +1557,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
}, },
_ => false _ => false
}; };
self.ir.tcx.sess.span_err( span_err!(self.ir.tcx.sess, sp, E0269, "not all control paths return a value");
sp, "not all control paths return a value");
if ends_with_stmt { if ends_with_stmt {
let last_stmt = body.stmts.first().unwrap(); let last_stmt = body.stmts.first().unwrap();
let original_span = original_sp(self.ir.tcx.sess.codemap(), let original_span = original_sp(self.ir.tcx.sess.codemap(),
@ -1575,7 +1574,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
} }
ty::FnDiverging ty::FnDiverging
if self.live_on_entry(entry_ln, self.s.clean_exit_var).is_some() => { if self.live_on_entry(entry_ln, self.s.clean_exit_var).is_some() => {
self.ir.tcx.sess.span_err(sp, span_err!(self.ir.tcx.sess, sp, E0270,
"computation may converge in a function marked as diverging"); "computation may converge in a function marked as diverging");
} }

View File

@ -33,7 +33,7 @@ pub fn update_recursion_limit(sess: &Session, krate: &ast::Crate) {
} }
} }
sess.span_err(attr.span, "malformed recursion limit attribute, \ span_err!(sess, attr.span, E0296, "malformed recursion limit attribute, \
expected #![recursion_limit=\"N\"]"); expected #![recursion_limit=\"N\"]");
} }
} }

View File

@ -396,10 +396,9 @@ impl<'a> LifetimeContext<'a> {
} }
fn unresolved_lifetime_ref(&self, lifetime_ref: &ast::Lifetime) { fn unresolved_lifetime_ref(&self, lifetime_ref: &ast::Lifetime) {
self.sess.span_err( span_err!(self.sess, lifetime_ref.span, E0261,
lifetime_ref.span, "use of undeclared lifetime name `{}`",
&format!("use of undeclared lifetime name `{}`", token::get_name(lifetime_ref.name));
token::get_name(lifetime_ref.name))[]);
} }
fn check_lifetime_defs(&mut self, old_scope: Scope, lifetimes: &Vec<ast::LifetimeDef>) { fn check_lifetime_defs(&mut self, old_scope: Scope, lifetimes: &Vec<ast::LifetimeDef>) {
@ -409,11 +408,9 @@ impl<'a> LifetimeContext<'a> {
let special_idents = [special_idents::static_lifetime]; let special_idents = [special_idents::static_lifetime];
for lifetime in lifetimes.iter() { for lifetime in lifetimes.iter() {
if special_idents.iter().any(|&i| i.name == lifetime.lifetime.name) { if special_idents.iter().any(|&i| i.name == lifetime.lifetime.name) {
self.sess.span_err( span_err!(self.sess, lifetime.lifetime.span, E0262,
lifetime.lifetime.span, "illegal lifetime parameter name: `{}`",
&format!("illegal lifetime parameter name: `{}`", token::get_name(lifetime.lifetime.name));
token::get_name(lifetime.lifetime.name))
[]);
} }
} }
@ -422,12 +419,10 @@ impl<'a> LifetimeContext<'a> {
let lifetime_j = &lifetimes[j]; let lifetime_j = &lifetimes[j];
if lifetime_i.lifetime.name == lifetime_j.lifetime.name { if lifetime_i.lifetime.name == lifetime_j.lifetime.name {
self.sess.span_err( span_err!(self.sess, lifetime_j.lifetime.span, E0263,
lifetime_j.lifetime.span, "lifetime name `{}` declared twice in \
&format!("lifetime name `{}` declared twice in \
the same scope", the same scope",
token::get_name(lifetime_j.lifetime.name)) token::get_name(lifetime_j.lifetime.name));
[]);
} }
} }

View File

@ -55,12 +55,10 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
let predicate = let predicate =
infcx.resolve_type_vars_if_possible(&obligation.predicate); infcx.resolve_type_vars_if_possible(&obligation.predicate);
if !predicate.references_error() { if !predicate.references_error() {
infcx.tcx.sess.span_err( span_err!(infcx.tcx.sess, obligation.cause.span, E0271,
obligation.cause.span,
format!(
"type mismatch resolving `{}`: {}", "type mismatch resolving `{}`: {}",
predicate.user_string(infcx.tcx), predicate.user_string(infcx.tcx),
ty::type_err_to_str(infcx.tcx, &error.err)).as_slice()); ty::type_err_to_str(infcx.tcx, &error.err));
note_obligation_cause(infcx, obligation); note_obligation_cause(infcx, obligation);
} }
} }
@ -97,28 +95,25 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
Position::ArgumentNamed(s) => match generic_map.get(s) { Position::ArgumentNamed(s) => match generic_map.get(s) {
Some(val) => Some(val.as_slice()), Some(val) => Some(val.as_slice()),
None => { None => {
infcx.tcx.sess span_err!(infcx.tcx.sess, err_sp, E0272,
.span_err(err_sp, "the #[rustc_on_unimplemented] \
format!("the #[rustc_on_unimplemented] \
attribute on \ attribute on \
trait definition for {} refers to \ trait definition for {} refers to \
non-existent type parameter {}", non-existent type parameter {}",
trait_str, s) trait_str, s);
.as_slice());
errored = true; errored = true;
None None
} }
}, },
_ => { _ => {
infcx.tcx.sess span_err!(infcx.tcx.sess, err_sp, E0273,
.span_err(err_sp, "the #[rustc_on_unimplemented] \
format!("the #[rustc_on_unimplemented] \
attribute on \ attribute on \
trait definition for {} must have named \ trait definition for {} must have named \
format arguments, \ format arguments, \
eg `#[rustc_on_unimplemented = \ eg `#[rustc_on_unimplemented = \
\"foo {{T}}\"]`", \"foo {{T}}\"]`",
trait_str).as_slice()); trait_str);
errored = true; errored = true;
None None
} }
@ -130,11 +125,11 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
report = Some(err); report = Some(err);
} }
} else { } else {
infcx.tcx.sess.span_err(err_sp, span_err!(infcx.tcx.sess, err_sp, E0274,
format!("the #[rustc_on_unimplemented] attribute on \ "the #[rustc_on_unimplemented] attribute on \
trait definition for {} must have a value, \ trait definition for {} must have a value, \
eg `#[rustc_on_unimplemented = \"foo\"]`", eg `#[rustc_on_unimplemented = \"foo\"]`",
trait_str).as_slice()); trait_str);
} }
break; break;
} }
@ -151,11 +146,9 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
// We could track the stack here more precisely if we wanted, I imagine. // We could track the stack here more precisely if we wanted, I imagine.
let predicate = let predicate =
infcx.resolve_type_vars_if_possible(&obligation.predicate); infcx.resolve_type_vars_if_possible(&obligation.predicate);
infcx.tcx.sess.span_err( span_err!(infcx.tcx.sess, obligation.cause.span, E0275,
obligation.cause.span,
format!(
"overflow evaluating the requirement `{}`", "overflow evaluating the requirement `{}`",
predicate.user_string(infcx.tcx)).as_slice()); predicate.user_string(infcx.tcx));
suggest_new_overflow_limit(infcx.tcx, obligation.cause.span); suggest_new_overflow_limit(infcx.tcx, obligation.cause.span);
@ -165,12 +158,10 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
SelectionError::Unimplemented => { SelectionError::Unimplemented => {
match &obligation.cause.code { match &obligation.cause.code {
&ObligationCauseCode::CompareImplMethodObligation => { &ObligationCauseCode::CompareImplMethodObligation => {
infcx.tcx.sess.span_err( span_err!(infcx.tcx.sess, obligation.cause.span, E0276,
obligation.cause.span,
format!(
"the requirement `{}` appears on the impl \ "the requirement `{}` appears on the impl \
method but not on the corresponding trait method", method but not on the corresponding trait method",
obligation.predicate.user_string(infcx.tcx)).as_slice()); obligation.predicate.user_string(infcx.tcx));;
} }
_ => { _ => {
match obligation.predicate { match obligation.predicate {
@ -180,12 +171,10 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
if !trait_predicate.references_error() { if !trait_predicate.references_error() {
let trait_ref = trait_predicate.to_poly_trait_ref(); let trait_ref = trait_predicate.to_poly_trait_ref();
infcx.tcx.sess.span_err( span_err!(infcx.tcx.sess, obligation.cause.span, E0277,
obligation.cause.span,
format!(
"the trait `{}` is not implemented for the type `{}`", "the trait `{}` is not implemented for the type `{}`",
trait_ref.user_string(infcx.tcx), trait_ref.user_string(infcx.tcx),
trait_ref.self_ty().user_string(infcx.tcx)).as_slice()); trait_ref.self_ty().user_string(infcx.tcx));
// Check if it has a custom "#[rustc_on_unimplemented]" // Check if it has a custom "#[rustc_on_unimplemented]"
// error message, report with that message if it does // error message, report with that message if it does
let custom_note = report_on_unimplemented(infcx, &*trait_ref.0, let custom_note = report_on_unimplemented(infcx, &*trait_ref.0,
@ -201,34 +190,28 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
let predicate = infcx.resolve_type_vars_if_possible(predicate); let predicate = infcx.resolve_type_vars_if_possible(predicate);
let err = infcx.equality_predicate(obligation.cause.span, let err = infcx.equality_predicate(obligation.cause.span,
&predicate).unwrap_err(); &predicate).unwrap_err();
infcx.tcx.sess.span_err( span_err!(infcx.tcx.sess, obligation.cause.span, E0278,
obligation.cause.span,
format!(
"the requirement `{}` is not satisfied (`{}`)", "the requirement `{}` is not satisfied (`{}`)",
predicate.user_string(infcx.tcx), predicate.user_string(infcx.tcx),
ty::type_err_to_str(infcx.tcx, &err)).as_slice()); ty::type_err_to_str(infcx.tcx, &err));
} }
ty::Predicate::RegionOutlives(ref predicate) => { ty::Predicate::RegionOutlives(ref predicate) => {
let predicate = infcx.resolve_type_vars_if_possible(predicate); let predicate = infcx.resolve_type_vars_if_possible(predicate);
let err = infcx.region_outlives_predicate(obligation.cause.span, let err = infcx.region_outlives_predicate(obligation.cause.span,
&predicate).unwrap_err(); &predicate).unwrap_err();
infcx.tcx.sess.span_err( span_err!(infcx.tcx.sess, obligation.cause.span, E0279,
obligation.cause.span,
format!(
"the requirement `{}` is not satisfied (`{}`)", "the requirement `{}` is not satisfied (`{}`)",
predicate.user_string(infcx.tcx), predicate.user_string(infcx.tcx),
ty::type_err_to_str(infcx.tcx, &err)).as_slice()); ty::type_err_to_str(infcx.tcx, &err));
} }
ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
let predicate = let predicate =
infcx.resolve_type_vars_if_possible(&obligation.predicate); infcx.resolve_type_vars_if_possible(&obligation.predicate);
infcx.tcx.sess.span_err( span_err!(infcx.tcx.sess, obligation.cause.span, E0280,
obligation.cause.span,
format!(
"the requirement `{}` is not satisfied", "the requirement `{}` is not satisfied",
predicate.user_string(infcx.tcx)).as_slice()); predicate.user_string(infcx.tcx));
} }
} }
} }
@ -239,15 +222,13 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
let expected_trait_ref = infcx.resolve_type_vars_if_possible(&*expected_trait_ref); let expected_trait_ref = infcx.resolve_type_vars_if_possible(&*expected_trait_ref);
let actual_trait_ref = infcx.resolve_type_vars_if_possible(&*actual_trait_ref); let actual_trait_ref = infcx.resolve_type_vars_if_possible(&*actual_trait_ref);
if !ty::type_is_error(actual_trait_ref.self_ty()) { if !ty::type_is_error(actual_trait_ref.self_ty()) {
infcx.tcx.sess.span_err( span_err!(infcx.tcx.sess, obligation.cause.span, E0281,
obligation.cause.span,
format!(
"type mismatch: the type `{}` implements the trait `{}`, \ "type mismatch: the type `{}` implements the trait `{}`, \
but the trait `{}` is required ({})", but the trait `{}` is required ({})",
expected_trait_ref.self_ty().user_string(infcx.tcx), expected_trait_ref.self_ty().user_string(infcx.tcx),
expected_trait_ref.user_string(infcx.tcx), expected_trait_ref.user_string(infcx.tcx),
actual_trait_ref.user_string(infcx.tcx), actual_trait_ref.user_string(infcx.tcx),
ty::type_err_to_str(infcx.tcx, e)).as_slice()); ty::type_err_to_str(infcx.tcx, e));
note_obligation_cause(infcx, obligation); note_obligation_cause(infcx, obligation);
} }
} }
@ -293,18 +274,14 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
infcx.tcx.lang_items.sized_trait() infcx.tcx.lang_items.sized_trait()
.map_or(false, |sized_id| sized_id == trait_ref.def_id()) .map_or(false, |sized_id| sized_id == trait_ref.def_id())
{ {
infcx.tcx.sess.span_err( span_err!(infcx.tcx.sess, obligation.cause.span, E0282,
obligation.cause.span,
format!(
"unable to infer enough type information about `{}`; \ "unable to infer enough type information about `{}`; \
type annotations required", type annotations required",
self_ty.user_string(infcx.tcx)).as_slice()); self_ty.user_string(infcx.tcx));
} else { } else {
infcx.tcx.sess.span_err( span_err!(infcx.tcx.sess, obligation.cause.span, E0283,
obligation.cause.span,
format!(
"type annotations required: cannot resolve `{}`", "type annotations required: cannot resolve `{}`",
predicate.user_string(infcx.tcx)).as_slice()); predicate.user_string(infcx.tcx));;
note_obligation_cause(infcx, obligation); note_obligation_cause(infcx, obligation);
} }
} }
@ -323,11 +300,9 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
_ => { _ => {
if !infcx.tcx.sess.has_errors() { if !infcx.tcx.sess.has_errors() {
infcx.tcx.sess.span_err( span_err!(infcx.tcx.sess, obligation.cause.span, E0284,
obligation.cause.span,
format!(
"type annotations required: cannot resolve `{}`", "type annotations required: cannot resolve `{}`",
predicate.user_string(infcx.tcx)).as_slice()); predicate.user_string(infcx.tcx));;
note_obligation_cause(infcx, obligation); note_obligation_cause(infcx, obligation);
} }
} }

View File

@ -379,11 +379,10 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
false false
} }
Err(Overflow) => { Err(Overflow) => {
infcx.tcx.sess.span_err( span_err!(infcx.tcx.sess, span, E0285,
span, "overflow evaluating whether `{}` is `{}`",
format!("overflow evaluating whether `{}` is `{}`", ty.user_string(infcx.tcx),
ty.user_string(infcx.tcx), bound.user_string(infcx.tcx));
bound.user_string(infcx.tcx)).as_slice());
suggest_new_overflow_limit(infcx.tcx, span); suggest_new_overflow_limit(infcx.tcx, span);
false false
} }

View File

@ -5369,15 +5369,13 @@ pub fn enum_variants<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
discriminant = val as Disr discriminant = val as Disr
} }
Ok(_) => { Ok(_) => {
cx.sess span_err!(cx.sess, e.span, E0304,
.span_err(e.span,
"expected signed integer constant"); "expected signed integer constant");
} }
Err(ref err) => { Err(ref err) => {
cx.sess span_err!(cx.sess, e.span, E0305,
.span_err(e.span, "expected constant: {}",
&format!("expected constant: {}", *err);
*err)[]);
} }
}, },
None => {} None => {}
@ -5851,9 +5849,9 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint {
const_eval::const_binary(_) => const_eval::const_binary(_) =>
"binary array" "binary array"
}; };
tcx.sess.span_err(count_expr.span, &format!( span_err!(tcx.sess, count_expr.span, E0306,
"expected positive integer for repeat count, found {}", "expected positive integer for repeat count, found {}",
found)[]); found);
} }
Err(_) => { Err(_) => {
let found = match count_expr.node { let found = match count_expr.node {
@ -5866,9 +5864,9 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint {
_ => _ =>
"non-constant expression" "non-constant expression"
}; };
tcx.sess.span_err(count_expr.span, &format!( span_err!(tcx.sess, count_expr.span, E0307,
"expected constant integer for repeat count, found {}", "expected constant integer for repeat count, found {}",
found)[]); found);
} }
} }
0 0

View File

@ -99,9 +99,9 @@ impl<'a> Context<'a> {
self.items.missing.push(lang_items::$item); self.items.missing.push(lang_items::$item);
} }
} else)* { } else)* {
self.sess.span_err(span, span_err!(self.sess, span, E0264,
format!("unknown external lang item: `{}`", "unknown external lang item: `{}`",
name).as_slice()); name);
} }
} }
} }

View File

@ -69,65 +69,23 @@ impl Session {
pub fn span_fatal(&self, sp: Span, msg: &str) -> ! { pub fn span_fatal(&self, sp: Span, msg: &str) -> ! {
self.diagnostic().span_fatal(sp, msg) self.diagnostic().span_fatal(sp, msg)
} }
pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> ! {
self.diagnostic().span_fatal_with_code(sp, msg, code)
}
pub fn fatal(&self, msg: &str) -> ! { pub fn fatal(&self, msg: &str) -> ! {
self.diagnostic().handler().fatal(msg) self.diagnostic().handler().fatal(msg)
} }
pub fn span_err(&self, sp: Span, msg: &str) { pub fn span_err(&self, sp: Span, msg: &str) {
// Conditions for enabling multi-line errors: match split_msg_into_multilines(msg) {
if !msg.contains("mismatched types") && Some(msg) => self.diagnostic().span_err(sp, &msg[]),
!msg.contains("type mismatch resolving") && None => self.diagnostic().span_err(sp, msg)
!msg.contains("if and else have incompatible types") &&
!msg.contains("if may be missing an else clause") &&
!msg.contains("match arms have incompatible types") &&
!msg.contains("structure constructor specifies a structure of type") {
return self.diagnostic().span_err(sp, msg);
} }
let first = Regex::new(r"[( ]expected").unwrap();
let second = Regex::new(r" found").unwrap();
let third = Regex::new(
r"\((values differ|lifetime|cyclic type of infinite size)").unwrap();
let mut new_msg = String::new();
let mut head = 0u;
// Insert `\n` before expected and found.
for (pos1, pos2) in first.find_iter(msg).zip(
second.find_iter(msg)) {
new_msg = new_msg +
// A `(` may be preceded by a space and it should be trimmed
msg[head..pos1.0].trim_right() + // prefix
"\n" + // insert before first
&msg[pos1.0..pos1.1] + // insert what first matched
&msg[pos1.1..pos2.0] + // between matches
"\n " + // insert before second
// 123
// `expected` is 3 char longer than `found`. To align the types, `found` gets
// 3 spaces prepended.
&msg[pos2.0..pos2.1]; // insert what second matched
head = pos2.1;
}
let mut tail = &msg[head..];
// Insert `\n` before any remaining messages which match.
for pos in third.find_iter(tail).take(1) {
// The end of the message may just be wrapped in `()` without `expected`/`found`.
// Push this also to a new line and add the final tail after.
new_msg = new_msg +
// `(` is usually preceded by a space and should be trimmed.
tail[..pos.0].trim_right() + // prefix
"\n" + // insert before paren
&tail[pos.0..]; // append the tail
tail = "";
}
new_msg.push_str(tail);
self.diagnostic().span_err(sp, &new_msg[])
} }
pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) { pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) {
self.diagnostic().span_err_with_code(sp, msg, code) match split_msg_into_multilines(msg) {
Some(msg) => self.diagnostic().span_err_with_code(sp, &msg[], code),
None => 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)
@ -285,6 +243,62 @@ impl Session {
} }
} }
fn split_msg_into_multilines(msg: &str) -> Option<String> {
// Conditions for enabling multi-line errors:
if !msg.contains("mismatched types") &&
!msg.contains("type mismatch resolving") &&
!msg.contains("if and else have incompatible types") &&
!msg.contains("if may be missing an else clause") &&
!msg.contains("match arms have incompatible types") &&
!msg.contains("structure constructor specifies a structure of type") {
return None
}
let first = Regex::new(r"[( ]expected").unwrap();
let second = Regex::new(r" found").unwrap();
let third = Regex::new(
r"\((values differ|lifetime|cyclic type of infinite size)").unwrap();
let mut new_msg = String::new();
let mut head = 0u;
// Insert `\n` before expected and found.
for (pos1, pos2) in first.find_iter(msg).zip(
second.find_iter(msg)) {
new_msg = new_msg +
// A `(` may be preceded by a space and it should be trimmed
msg[head..pos1.0].trim_right() + // prefix
"\n" + // insert before first
&msg[pos1.0..pos1.1] + // insert what first matched
&msg[pos1.1..pos2.0] + // between matches
"\n " + // insert before second
// 123
// `expected` is 3 char longer than `found`. To align the types, `found` gets
// 3 spaces prepended.
&msg[pos2.0..pos2.1]; // insert what second matched
head = pos2.1;
}
let mut tail = &msg[head..];
// Insert `\n` before any remaining messages which match.
for pos in third.find_iter(tail).take(1) {
// The end of the message may just be wrapped in `()` without `expected`/`found`.
// Push this also to a new line and add the final tail after.
new_msg = new_msg +
// `(` is usually preceded by a space and should be trimmed.
tail[..pos.0].trim_right() + // prefix
"\n" + // insert before paren
&tail[pos.0..]; // append the tail
tail = "";
}
new_msg.push_str(tail);
return Some(new_msg)
}
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) registry: diagnostics::registry::Registry)

View File

@ -61,7 +61,6 @@ use rustc::lint::Lint;
use rustc::lint; use rustc::lint;
use rustc::metadata; use rustc::metadata;
use rustc::metadata::creader::CrateOrString::Str; use rustc::metadata::creader::CrateOrString::Str;
use rustc::DIAGNOSTICS;
use rustc::util::common::time; use rustc::util::common::time;
use std::cmp::Ordering::Equal; use std::cmp::Ordering::Equal;
@ -98,7 +97,7 @@ fn run_compiler(args: &[String]) {
None => return None => return
}; };
let descriptions = diagnostics::registry::Registry::new(&DIAGNOSTICS); let descriptions = diagnostics_registry();
match matches.opt_str("explain") { match matches.opt_str("explain") {
Some(ref code) => { Some(ref code) => {
match descriptions.find_description(&code[]) { match descriptions.find_description(&code[]) {
@ -659,8 +658,20 @@ pub fn monitor<F:FnOnce()+Send>(f: F) {
} }
} }
pub fn diagnostics_registry() -> diagnostics::registry::Registry {
use syntax::diagnostics::registry::Registry;
let all_errors = Vec::new() +
rustc::diagnostics::DIAGNOSTICS.as_slice() +
rustc_typeck::diagnostics::DIAGNOSTICS.as_slice() +
rustc_resolve::diagnostics::DIAGNOSTICS.as_slice();
Registry::new(&*all_errors)
}
pub fn main() { pub fn main() {
let args = std::os::args(); let args = std::os::args();
let result = run(args); let result = run(args);
std::os::set_exit_status(result); std::os::set_exit_status(result);
} }

View 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.
#![allow(non_snake_case)]
register_diagnostics! {
E0157,
E0153,
E0251, // a named type or value has already been imported in this module
E0252, // a named type or value has already been imported in this module
E0253, // not directly importable
E0254, // import conflicts with imported crate in this module
E0255, // import conflicts with value in this module
E0256, // import conflicts with type in this module
E0257, // inherent implementations are only allowen on types defined in the current module
E0258, // import conflicts with existing submodule
E0259, // an extern crate has already been imported into this module
E0260 // name conflicts with an external crate that has been imported into this module
}
__build_diagnostic_array! { DIAGNOSTICS }

View File

@ -97,6 +97,10 @@ use std::mem::replace;
use std::rc::{Rc, Weak}; use std::rc::{Rc, Weak};
use std::uint; use std::uint;
// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;
mod check_unused; mod check_unused;
mod record_exports; mod record_exports;
mod build_reduced_graph; mod build_reduced_graph;
@ -1718,7 +1722,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
in this module", in this module",
namespace_name, namespace_name,
token::get_name(name).get()); token::get_name(name).get());
self.session.span_err(import_directive.span, msg.as_slice()); span_err!(self.session, import_directive.span, E0251, "{}", msg.as_slice());
} else { } else {
let target = Target::new(containing_module.clone(), let target = Target::new(containing_module.clone(),
name_bindings.clone(), name_bindings.clone(),
@ -1765,7 +1769,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ValueNS => "value", ValueNS => "value",
}, },
token::get_name(name).get()); token::get_name(name).get());
self.session.span_err(import_span, &msg[]); span_err!(self.session, import_span, E0252, "{}", &msg[]);
} }
Some(_) | None => {} Some(_) | None => {}
} }
@ -1780,7 +1784,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if !name_bindings.defined_in_namespace_with(namespace, IMPORTABLE) { if !name_bindings.defined_in_namespace_with(namespace, IMPORTABLE) {
let msg = format!("`{}` is not directly importable", let msg = format!("`{}` is not directly importable",
token::get_name(name)); token::get_name(name));
self.session.span_err(import_span, &msg[]); span_err!(self.session, import_span, E0253, "{}", &msg[]);
} }
} }
@ -1805,7 +1809,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
crate in this module \ crate in this module \
(maybe you meant `use {0}::*`?)", (maybe you meant `use {0}::*`?)",
token::get_name(name).get()); token::get_name(name).get());
self.session.span_err(import_span, &msg[]); span_err!(self.session, import_span, E0254, "{}", &msg[]);
} }
Some(_) | None => {} Some(_) | None => {}
} }
@ -1827,7 +1831,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let msg = format!("import `{}` conflicts with value \ let msg = format!("import `{}` conflicts with value \
in this module", in this module",
token::get_name(name).get()); token::get_name(name).get());
self.session.span_err(import_span, &msg[]); span_err!(self.session, import_span, E0255, "{}", &msg[]);
if let Some(span) = value.value_span { if let Some(span) = value.value_span {
self.session.span_note(span, self.session.span_note(span,
"conflicting value here"); "conflicting value here");
@ -1845,7 +1849,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let msg = format!("import `{}` conflicts with type in \ let msg = format!("import `{}` conflicts with type in \
this module", this module",
token::get_name(name).get()); token::get_name(name).get());
self.session.span_err(import_span, &msg[]); span_err!(self.session, import_span, E0256, "{}", &msg[]);
if let Some(span) = ty.type_span { if let Some(span) = ty.type_span {
self.session.span_note(span, self.session.span_note(span,
"note conflicting type here") "note conflicting type here")
@ -1858,7 +1862,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let msg = format!("inherent implementations \ let msg = format!("inherent implementations \
are only allowed on types \ are only allowed on types \
defined in the current module"); defined in the current module");
self.session.span_err(span, &msg[]); span_err!(self.session, span, E0257, "{}", &msg[]);
self.session.span_note(import_span, self.session.span_note(import_span,
"import from other module here") "import from other module here")
} }
@ -1867,7 +1871,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let msg = format!("import `{}` conflicts with existing \ let msg = format!("import `{}` conflicts with existing \
submodule", submodule",
token::get_name(name).get()); token::get_name(name).get());
self.session.span_err(import_span, &msg[]); span_err!(self.session, import_span, E0258, "{}", &msg[]);
if let Some(span) = ty.type_span { if let Some(span) = ty.type_span {
self.session.span_note(span, self.session.span_note(span,
"note conflicting module here") "note conflicting module here")
@ -1893,11 +1897,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} }
if module.external_module_children.borrow().contains_key(&name) { if module.external_module_children.borrow().contains_key(&name) {
self.session span_err!(self.session, span, E0259,
.span_err(span, "an external crate named `{}` has already \
&format!("an external crate named `{}` has already \
been imported into this module", been imported into this module",
token::get_name(name).get())[]); token::get_name(name).get());
} }
} }
@ -1911,12 +1914,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} }
if module.external_module_children.borrow().contains_key(&name) { if module.external_module_children.borrow().contains_key(&name) {
self.session span_err!(self.session, span, E0260,
.span_err(span, "the name `{}` conflicts with an external \
&format!("the name `{}` conflicts with an external \
crate that has been imported into this \ crate that has been imported into this \
module", module",
token::get_name(name).get())[]); token::get_name(name).get());
} }
} }

View File

@ -100,8 +100,7 @@ pub trait AstConv<'tcx> {
-> Ty<'tcx> -> Ty<'tcx>
{ {
if ty::binds_late_bound_regions(self.tcx(), &poly_trait_ref) { if ty::binds_late_bound_regions(self.tcx(), &poly_trait_ref) {
self.tcx().sess.span_err( span_err!(self.tcx().sess, span, E0212,
span,
"cannot extract an associated type from a higher-ranked trait bound \ "cannot extract an associated type from a higher-ranked trait bound \
in this context"); in this context");
self.tcx().types.err self.tcx().types.err
@ -119,8 +118,7 @@ pub trait AstConv<'tcx> {
_item_name: ast::Name) _item_name: ast::Name)
-> Ty<'tcx> -> Ty<'tcx>
{ {
self.tcx().sess.span_err( span_err!(self.tcx().sess, span, E0213,
span,
"associated types are not accepted in this context"); "associated types are not accepted in this context");
self.tcx().types.err self.tcx().types.err
@ -268,8 +266,7 @@ pub fn ast_path_substs_for_ty<'tcx>(
convert_angle_bracketed_parameters(this, rscope, data) convert_angle_bracketed_parameters(this, rscope, data)
} }
ast::ParenthesizedParameters(ref data) => { ast::ParenthesizedParameters(ref data) => {
tcx.sess.span_err( span_err!(tcx.sess, path.span, E0214,
path.span,
"parenthesized parameters may only be used with a trait"); "parenthesized parameters may only be used with a trait");
(Vec::new(), convert_parenthesized_parameters(this, data), Vec::new()) (Vec::new(), convert_parenthesized_parameters(this, data), Vec::new())
} }
@ -342,22 +339,22 @@ fn create_substs_for_ast_path<'tcx>(
} else { } else {
"expected" "expected"
}; };
this.tcx().sess.span_fatal(span, span_fatal!(this.tcx().sess, span, E0243,
&format!("wrong number of type arguments: {} {}, found {}", "wrong number of type arguments: {} {}, found {}",
expected, expected,
required_ty_param_count, required_ty_param_count,
supplied_ty_param_count)[]); supplied_ty_param_count);
} else if supplied_ty_param_count > formal_ty_param_count { } else if supplied_ty_param_count > formal_ty_param_count {
let expected = if required_ty_param_count < formal_ty_param_count { let expected = if required_ty_param_count < formal_ty_param_count {
"expected at most" "expected at most"
} else { } else {
"expected" "expected"
}; };
this.tcx().sess.span_fatal(span, span_fatal!(this.tcx().sess, span, E0244,
&format!("wrong number of type arguments: {} {}, found {}", "wrong number of type arguments: {} {}, found {}",
expected, expected,
formal_ty_param_count, formal_ty_param_count,
supplied_ty_param_count)[]); supplied_ty_param_count);
} }
let mut substs = Substs::new_type(types, regions); let mut substs = Substs::new_type(types, regions);
@ -560,10 +557,9 @@ pub fn instantiate_trait_ref<'tcx>(
trait_ref trait_ref
} }
_ => { _ => {
this.tcx().sess.span_fatal( span_fatal!(this.tcx().sess, ast_trait_ref.path.span, E0245,
ast_trait_ref.path.span, "`{}` is not a trait",
&format!("`{}` is not a trait", ast_trait_ref.path.user_string(this.tcx()));
ast_trait_ref.path.user_string(this.tcx()))[]);
} }
} }
} }
@ -610,7 +606,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
if !this.tcx().sess.features.borrow().unboxed_closures && if !this.tcx().sess.features.borrow().unboxed_closures &&
this.tcx().lang_items.fn_trait_kind(trait_def_id).is_some() this.tcx().lang_items.fn_trait_kind(trait_def_id).is_some()
{ {
this.tcx().sess.span_err(path.span, span_err!(this.tcx().sess, path.span, E0215,
"angle-bracket notation is not stable when \ "angle-bracket notation is not stable when \
used with the `Fn` family of traits, use parentheses"); used with the `Fn` family of traits, use parentheses");
span_help!(this.tcx().sess, path.span, span_help!(this.tcx().sess, path.span,
@ -626,7 +622,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
if !this.tcx().sess.features.borrow().unboxed_closures && if !this.tcx().sess.features.borrow().unboxed_closures &&
this.tcx().lang_items.fn_trait_kind(trait_def_id).is_none() this.tcx().lang_items.fn_trait_kind(trait_def_id).is_none()
{ {
this.tcx().sess.span_err(path.span, span_err!(this.tcx().sess, path.span, E0216,
"parenthetical notation is only stable when \ "parenthetical notation is only stable when \
used with the `Fn` family of traits"); used with the `Fn` family of traits");
span_help!(this.tcx().sess, path.span, span_help!(this.tcx().sess, path.span,
@ -738,32 +734,29 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
} }
if candidates.len() > 1 { if candidates.len() > 1 {
tcx.sess.span_err( span_err!(tcx.sess, binding.span, E0217,
binding.span, "ambiguous associated type: `{}` defined in multiple supertraits `{}`",
format!("ambiguous associated type: `{}` defined in multiple supertraits `{}`",
token::get_name(binding.item_name), token::get_name(binding.item_name),
candidates.user_string(tcx)).as_slice()); candidates.user_string(tcx));
return Err(ErrorReported); return Err(ErrorReported);
} }
let candidate = match candidates.pop() { let candidate = match candidates.pop() {
Some(c) => c, Some(c) => c,
None => { None => {
tcx.sess.span_err( span_err!(tcx.sess, binding.span, E0218,
binding.span, "no associated type `{}` defined in `{}`",
format!("no associated type `{}` defined in `{}`",
token::get_name(binding.item_name), token::get_name(binding.item_name),
trait_ref.user_string(tcx)).as_slice()); trait_ref.user_string(tcx));
return Err(ErrorReported); return Err(ErrorReported);
} }
}; };
if ty::binds_late_bound_regions(tcx, &candidate) { if ty::binds_late_bound_regions(tcx, &candidate) {
tcx.sess.span_err( span_err!(tcx.sess, binding.span, E0219,
binding.span, "associated type `{}` defined in higher-ranked supertrait `{}`",
format!("associated type `{}` defined in higher-ranked supertrait `{}`",
token::get_name(binding.item_name), token::get_name(binding.item_name),
candidate.user_string(tcx)).as_slice()); candidate.user_string(tcx));
return Err(ErrorReported); return Err(ErrorReported);
} }
@ -964,18 +957,18 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
} }
if suitable_bounds.len() == 0 { if suitable_bounds.len() == 0 {
tcx.sess.span_err(ast_ty.span, span_err!(tcx.sess, ast_ty.span, E0220,
format!("associated type `{}` not found for type parameter `{}`", "associated type `{}` not found for type parameter `{}`",
token::get_name(assoc_name), token::get_name(assoc_name),
token::get_name(ty_param_name)).as_slice()); token::get_name(ty_param_name));
return this.tcx().types.err; return this.tcx().types.err;
} }
if suitable_bounds.len() > 1 { if suitable_bounds.len() > 1 {
tcx.sess.span_err(ast_ty.span, span_err!(tcx.sess, ast_ty.span, E0221,
format!("ambiguous associated type `{}` in bounds of `{}`", "ambiguous associated type `{}` in bounds of `{}`",
token::get_name(assoc_name), token::get_name(assoc_name),
token::get_name(ty_param_name)).as_slice()); token::get_name(ty_param_name));
for suitable_bound in suitable_bounds.iter() { for suitable_bound in suitable_bounds.iter() {
span_note!(this.tcx().sess, ast_ty.span, span_note!(this.tcx().sess, ast_ty.span,
@ -1042,7 +1035,7 @@ pub fn ast_ty_to_ty<'tcx>(
match ast_ty_to_ty_cache.get(&ast_ty.id) { match ast_ty_to_ty_cache.get(&ast_ty.id) {
Some(&ty::atttce_resolved(ty)) => return ty, Some(&ty::atttce_resolved(ty)) => return ty,
Some(&ty::atttce_unresolved) => { Some(&ty::atttce_unresolved) => {
tcx.sess.span_fatal(ast_ty.span, span_fatal!(tcx.sess, ast_ty.span, E0246,
"illegal recursive type; insert an enum \ "illegal recursive type; insert an enum \
or struct in the cycle, if this is \ or struct in the cycle, if this is \
desired"); desired");
@ -1093,7 +1086,7 @@ pub fn ast_ty_to_ty<'tcx>(
ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ), ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ),
ast::TyBareFn(ref bf) => { ast::TyBareFn(ref bf) => {
if bf.decl.variadic && bf.abi != abi::C { if bf.decl.variadic && bf.abi != abi::C {
tcx.sess.span_err(ast_ty.span, span_err!(tcx.sess, ast_ty.span, E0222,
"variadic function must have C calling convention"); "variadic function must have C calling convention");
} }
let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl); let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl);
@ -1142,9 +1135,9 @@ pub fn ast_ty_to_ty<'tcx>(
ty::mk_self_type(tcx) ty::mk_self_type(tcx)
} }
def::DefMod(id) => { def::DefMod(id) => {
tcx.sess.span_fatal(ast_ty.span, span_fatal!(tcx.sess, ast_ty.span, E0247,
&format!("found module name used as a type: {}", "found module name used as a type: {}",
tcx.map.node_to_string(id.node))[]); tcx.map.node_to_string(id.node));
} }
def::DefPrimTy(_) => { def::DefPrimTy(_) => {
panic!("DefPrimTy arm missed in previous ast_ty_to_prim_ty call"); panic!("DefPrimTy arm missed in previous ast_ty_to_prim_ty call");
@ -1152,8 +1145,8 @@ pub fn ast_ty_to_ty<'tcx>(
def::DefAssociatedTy(trait_type_id) => { def::DefAssociatedTy(trait_type_id) => {
let path_str = tcx.map.path_to_string( let path_str = tcx.map.path_to_string(
tcx.map.get_parent(trait_type_id.node)); tcx.map.get_parent(trait_type_id.node));
tcx.sess.span_err(ast_ty.span, span_err!(tcx.sess, ast_ty.span, E0223,
&format!("ambiguous associated \ "ambiguous associated \
type; specify the type \ type; specify the type \
using the syntax `<Type \ using the syntax `<Type \
as {}>::{}`", as {}>::{}`",
@ -1163,17 +1156,17 @@ pub fn ast_ty_to_ty<'tcx>(
.last() .last()
.unwrap() .unwrap()
.identifier) .identifier)
.get())[]); .get());
this.tcx().types.err this.tcx().types.err
} }
def::DefAssociatedPath(provenance, assoc_ident) => { def::DefAssociatedPath(provenance, assoc_ident) => {
associated_path_def_to_ty(this, ast_ty, provenance, assoc_ident.name) associated_path_def_to_ty(this, ast_ty, provenance, assoc_ident.name)
} }
_ => { _ => {
tcx.sess.span_fatal(ast_ty.span, span_fatal!(tcx.sess, ast_ty.span, E0248,
&format!("found value name used \ "found value name used \
as a type: {:?}", as a type: {:?}",
a_def)[]); a_def);
} }
} }
} }
@ -1191,17 +1184,16 @@ pub fn ast_ty_to_ty<'tcx>(
ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty),
Some(i as uint)), Some(i as uint)),
_ => { _ => {
tcx.sess.span_fatal( span_fatal!(tcx.sess, ast_ty.span, E0249,
ast_ty.span, "expected constant expr for array length"); "expected constant expr for array length");
} }
} }
} }
Err(ref r) => { Err(ref r) => {
tcx.sess.span_fatal( span_fatal!(tcx.sess, ast_ty.span, E0250,
ast_ty.span, "expected constant expr for array \
&format!("expected constant expr for array \
length: {}", length: {}",
*r)[]); *r);
} }
} }
} }
@ -1557,8 +1549,7 @@ fn conv_ty_poly_trait_ref<'tcx>(
None, None,
&mut projection_bounds)) &mut projection_bounds))
} else { } else {
this.tcx().sess.span_err( span_err!(this.tcx().sess, span, E0224,
span,
"at least one non-builtin trait is required for an object type"); "at least one non-builtin trait is required for an object type");
None None
}; };
@ -1593,10 +1584,9 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
if !trait_bounds.is_empty() { if !trait_bounds.is_empty() {
let b = &trait_bounds[0]; let b = &trait_bounds[0];
this.tcx().sess.span_err( span_err!(this.tcx().sess, b.trait_ref.path.span, E0225,
b.trait_ref.path.span, "only the builtin traits can be used \
&format!("only the builtin traits can be used \ as closure or object bounds");
as closure or object bounds")[]);
} }
let region_bound = compute_region_bound(this, let region_bound = compute_region_bound(this,
@ -1633,9 +1623,8 @@ fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
builtin_bounds.repr(tcx)); builtin_bounds.repr(tcx));
if explicit_region_bounds.len() > 1 { if explicit_region_bounds.len() > 1 {
tcx.sess.span_err( span_err!(tcx.sess, explicit_region_bounds[1].span, E0226,
explicit_region_bounds[1].span, "only a single explicit lifetime bound is permitted");
format!("only a single explicit lifetime bound is permitted").as_slice());
} }
if explicit_region_bounds.len() != 0 { if explicit_region_bounds.len() != 0 {
@ -1666,10 +1655,9 @@ fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
// error. // error.
let r = derived_region_bounds[0]; let r = derived_region_bounds[0];
if derived_region_bounds.slice_from(1).iter().any(|r1| r != *r1) { if derived_region_bounds.slice_from(1).iter().any(|r1| r != *r1) {
tcx.sess.span_err( span_err!(tcx.sess, span, E0227,
span, "ambiguous lifetime bound, \
&format!("ambiguous lifetime bound, \ explicit lifetime bound required");
explicit lifetime bound required")[]);
} }
return Some(r); return Some(r);
} }
@ -1693,9 +1681,8 @@ fn compute_region_bound<'tcx>(
match rscope.default_region_bound(span) { match rscope.default_region_bound(span) {
Some(r) => { r } Some(r) => { r }
None => { None => {
this.tcx().sess.span_err( span_err!(this.tcx().sess, span, E0228,
span, "explicit lifetime bound required");
&format!("explicit lifetime bound required")[]);
ty::ReStatic ty::ReStatic
} }
} }
@ -1779,8 +1766,7 @@ fn prohibit_projections<'tcx>(tcx: &ty::ctxt<'tcx>,
bindings: &[ConvertedBinding<'tcx>]) bindings: &[ConvertedBinding<'tcx>])
{ {
for binding in bindings.iter().take(1) { for binding in bindings.iter().take(1) {
tcx.sess.span_err( span_err!(tcx.sess, binding.span, E0229,
binding.span,
"associated type bindings are not allowed here"); "associated type bindings are not allowed here");
} }
} }

View File

@ -50,10 +50,9 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
check_unboxed_closure(fcx, expr, kind, decl, body, None); check_unboxed_closure(fcx, expr, kind, decl, body, None);
fcx.ccx.tcx.sess.span_err( span_err!(fcx.ccx.tcx.sess, expr.span, E0187,
expr.span,
"can't infer the \"kind\" of the closure, explicitly annotate it. e.g. \ "can't infer the \"kind\" of the closure, explicitly annotate it. e.g. \
`|&:| {}`"); `|&:| {{}}`");
}, },
Some((sig, kind)) => { Some((sig, kind)) => {
check_unboxed_closure(fcx, expr, kind, decl, body, Some(sig)); check_unboxed_closure(fcx, expr, kind, decl, body, Some(sig));

View File

@ -59,23 +59,21 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
(&ty::StaticExplicitSelfCategory, (&ty::StaticExplicitSelfCategory,
&ty::StaticExplicitSelfCategory) => {} &ty::StaticExplicitSelfCategory) => {}
(&ty::StaticExplicitSelfCategory, _) => { (&ty::StaticExplicitSelfCategory, _) => {
tcx.sess.span_err( span_err!(tcx.sess, impl_m_span, E0185,
impl_m_span, "method `{}` has a `{}` declaration in the impl, \
format!("method `{}` has a `{}` declaration in the impl, \
but not in the trait", but not in the trait",
token::get_name(trait_m.name), token::get_name(trait_m.name),
ppaux::explicit_self_category_to_str( ppaux::explicit_self_category_to_str(
&impl_m.explicit_self)).as_slice()); &impl_m.explicit_self));
return; return;
} }
(_, &ty::StaticExplicitSelfCategory) => { (_, &ty::StaticExplicitSelfCategory) => {
tcx.sess.span_err( span_err!(tcx.sess, impl_m_span, E0186,
impl_m_span, "method `{}` has a `{}` declaration in the trait, \
format!("method `{}` has a `{}` declaration in the trait, \
but not in the impl", but not in the impl",
token::get_name(trait_m.name), token::get_name(trait_m.name),
ppaux::explicit_self_category_to_str( ppaux::explicit_self_category_to_str(
&trait_m.explicit_self)).as_slice()); &trait_m.explicit_self));
return; return;
} }
_ => { _ => {
@ -400,11 +398,10 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
// are zero. Since I don't quite know how to phrase things at // are zero. Since I don't quite know how to phrase things at
// the moment, give a kind of vague error message. // the moment, give a kind of vague error message.
if trait_params.len() != impl_params.len() { if trait_params.len() != impl_params.len() {
tcx.sess.span_err( span_err!(tcx.sess, span, E0195,
span, "lifetime parameters or bounds on method `{}` do \
&format!("lifetime parameters or bounds on method `{}` do \
not match the trait declaration", not match the trait declaration",
token::get_name(impl_m.name))[]); token::get_name(impl_m.name));
return false; return false;
} }

View File

@ -801,16 +801,15 @@ fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
}) { }) {
Some(_) => (), Some(_) => (),
None => { None => {
ccx.tcx.sess.span_err(attr.span, span_err!(ccx.tcx.sess, attr.span, E0230,
format!("there is no type parameter \ "there is no type parameter \
{} on trait {}", {} on trait {}",
s, item.ident.as_str()) s, item.ident.as_str());
.as_slice());
} }
}, },
// `{:1}` and `{}` are not to be used // `{:1}` and `{}` are not to be used
Position::ArgumentIs(_) | Position::ArgumentNext => { Position::ArgumentIs(_) | Position::ArgumentNext => {
ccx.tcx.sess.span_err(attr.span, span_err!(ccx.tcx.sess, attr.span, E0231,
"only named substitution \ "only named substitution \
parameters are allowed"); parameters are allowed");
} }
@ -818,7 +817,7 @@ fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
} }
} }
} else { } else {
ccx.tcx.sess.span_err(attr.span, span_err!(ccx.tcx.sess, attr.span, E0232,
"this attribute must have a value, \ "this attribute must have a value, \
eg `#[rustc_on_unimplemented = \"foo\"]`") eg `#[rustc_on_unimplemented = \"foo\"]`")
} }
@ -2099,8 +2098,8 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
let trait_did = match fcx.tcx().lang_items.require(IteratorItem) { let trait_did = match fcx.tcx().lang_items.require(IteratorItem) {
Ok(trait_did) => trait_did, Ok(trait_did) => trait_did,
Err(ref err_string) => { Err(ref err_string) => {
fcx.tcx().sess.span_err(iterator_expr.span, span_err!(fcx.tcx().sess, iterator_expr.span, E0233,
&err_string[]); "{}", &err_string[]);
return fcx.tcx().types.err return fcx.tcx().types.err
} }
}; };
@ -2123,11 +2122,10 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
if !ty::type_is_error(true_expr_type) { if !ty::type_is_error(true_expr_type) {
let ty_string = fcx.infcx().ty_to_string(true_expr_type); let ty_string = fcx.infcx().ty_to_string(true_expr_type);
fcx.tcx().sess.span_err(iterator_expr.span, span_err!(fcx.tcx().sess, iterator_expr.span, E0234,
&format!("`for` loop expression has type `{}` which does \ "`for` loop expression has type `{}` which does \
not implement the `Iterator` trait; \ not implement the `Iterator` trait; \
maybe try .iter()", maybe try .iter()", ty_string);
ty_string)[]);
} }
fcx.tcx().types.err fcx.tcx().types.err
} }
@ -2162,11 +2160,10 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
fcx.tcx().types.err fcx.tcx().types.err
} }
_ => { _ => {
fcx.tcx().sess.span_err(iterator_expr.span, span_err!(fcx.tcx().sess, iterator_expr.span, E0239,
&format!("`next` method of the `Iterator` \ "`next` method of the `Iterator` \
trait has an unexpected type `{}`", trait has an unexpected type `{}`",
fcx.infcx().ty_to_string(return_type)) fcx.infcx().ty_to_string(return_type));
[]);
fcx.tcx().types.err fcx.tcx().types.err
} }
} }
@ -3880,10 +3877,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
Err(type_error) => { Err(type_error) => {
let type_error_description = let type_error_description =
ty::type_err_to_str(tcx, &type_error); ty::type_err_to_str(tcx, &type_error);
fcx.tcx() span_err!(fcx.tcx().sess, path.span, E0235,
.sess "structure constructor specifies a \
.span_err(path.span,
&format!("structure constructor specifies a \
structure of type `{}`, but this \ structure of type `{}`, but this \
structure has type `{}`: {}", structure has type `{}`: {}",
fcx.infcx() fcx.infcx()
@ -3891,7 +3886,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
fcx.infcx() fcx.infcx()
.ty_to_string( .ty_to_string(
actual_structure_type), actual_structure_type),
type_error_description)[]); type_error_description);
ty::note_and_explain_type_err(tcx, &type_error); ty::note_and_explain_type_err(tcx, &type_error);
} }
} }
@ -4012,7 +4007,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
ty::mk_struct(tcx, did, tcx.mk_substs(substs)) ty::mk_struct(tcx, did, tcx.mk_substs(substs))
} else { } else {
tcx.sess.span_err(expr.span, "No lang item for range syntax"); span_err!(tcx.sess, expr.span, E0236, "no lang item for range syntax");
fcx.tcx().types.err fcx.tcx().types.err
} }
} }
@ -4022,7 +4017,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
let substs = Substs::new_type(vec![], vec![]); let substs = Substs::new_type(vec![], vec![]);
ty::mk_struct(tcx, did, tcx.mk_substs(substs)) ty::mk_struct(tcx, did, tcx.mk_substs(substs))
} else { } else {
tcx.sess.span_err(expr.span, "No lang item for range syntax"); span_err!(tcx.sess, expr.span, E0237, "no lang item for range syntax");
fcx.tcx().types.err fcx.tcx().types.err
} }
} }
@ -4872,8 +4867,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
} }
ast::ParenthesizedParameters(ref data) => { ast::ParenthesizedParameters(ref data) => {
fcx.tcx().sess.span_err( span_err!(fcx.tcx().sess, span, E0238,
span,
"parenthesized parameters may only be used with a trait"); "parenthesized parameters may only be used with a trait");
push_explicit_parenthesized_parameters_from_segment_to_substs( push_explicit_parenthesized_parameters_from_segment_to_substs(
fcx, space, span, type_defs, data, substs); fcx, space, span, type_defs, data, substs);
@ -5230,7 +5224,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
"get_tydesc" => { "get_tydesc" => {
let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) { let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
Ok(t) => t, Ok(t) => t,
Err(s) => { tcx.sess.span_fatal(it.span, &s[]); } Err(s) => { span_fatal!(tcx.sess, it.span, E0240, "{}", &s[]); }
}; };
let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt { let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
ty: tydesc_ty, ty: tydesc_ty,

View File

@ -51,7 +51,7 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
{ {
let object_trait = object_trait(&object_trait_ty); let object_trait = object_trait(&object_trait_ty);
if !mutability_allowed(referent_mutbl, target_mutbl) { if !mutability_allowed(referent_mutbl, target_mutbl) {
fcx.tcx().sess.span_err(source_expr.span, span_err!(fcx.tcx().sess, source_expr.span, E0188,
"types differ in mutability"); "types differ in mutability");
} else { } else {
// Ensure that if &'a T is cast to &'b Trait, then T : Trait // Ensure that if &'a T is cast to &'b Trait, then T : Trait
@ -70,19 +70,17 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
} }
(_, &ty::ty_uniq(..)) => { (_, &ty::ty_uniq(..)) => {
fcx.ccx.tcx.sess.span_err( span_err!(fcx.ccx.tcx.sess, source_expr.span, E0189,
source_expr.span, "can only cast a boxed pointer \
&format!("can only cast an boxed pointer \
to a boxed object, not a {}", to a boxed object, not a {}",
ty::ty_sort_string(fcx.tcx(), source_ty))[]); ty::ty_sort_string(fcx.tcx(), source_ty));
} }
(_, &ty::ty_rptr(..)) => { (_, &ty::ty_rptr(..)) => {
fcx.ccx.tcx.sess.span_err( span_err!(fcx.ccx.tcx.sess, source_expr.span, E0190,
source_expr.span, "can only cast a &-pointer \
&format!("can only cast a &-pointer \
to an &-object, not a {}", to an &-object, not a {}",
ty::ty_sort_string(fcx.tcx(), source_ty))[]); ty::ty_sort_string(fcx.tcx(), source_ty));
} }
_ => { _ => {
@ -272,11 +270,10 @@ fn check_object_type_binds_all_associated_types<'tcx>(tcx: &ty::ctxt<'tcx>,
} }
for (trait_def_id, name) in associated_types.into_iter() { for (trait_def_id, name) in associated_types.into_iter() {
tcx.sess.span_err( span_err!(tcx.sess, span, E0191,
span, "the value of the associated type `{}` (from the trait `{}`) must be specified",
format!("the value of the associated type `{}` (from the trait `{}`) must be specified",
name.user_string(tcx), name.user_string(tcx),
ty::item_path_str(tcx, trait_def_id)).as_slice()); ty::item_path_str(tcx, trait_def_id));
} }
} }

View File

@ -81,10 +81,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) { match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
Some(ty::BoundSend) | Some(ty::BoundSync) => {} Some(ty::BoundSend) | Some(ty::BoundSync) => {}
Some(_) | None => { Some(_) | None => {
ccx.tcx.sess.span_err( span_err!(ccx.tcx.sess, item.span, E0192,
item.span, "negative impls are currently \
format!("negative impls are currently \ allowed just for `Send` and `Sync`")
allowed just for `Send` and `Sync`").as_slice())
} }
} }
} }
@ -302,12 +301,11 @@ fn reject_non_type_param_bounds<'tcx>(tcx: &ty::ctxt<'tcx>,
fn report_bound_error<'t>(tcx: &ty::ctxt<'t>, fn report_bound_error<'t>(tcx: &ty::ctxt<'t>,
span: Span, span: Span,
bounded_ty: ty::Ty<'t>) { bounded_ty: ty::Ty<'t>) {
tcx.sess.span_err( span_err!(tcx.sess, span, E0193,
span, "cannot bound type `{}`, where clause \
format!("cannot bound type `{}`, where clause \
bounds may only be attached to types involving \ bounds may only be attached to types involving \
type parameters", type parameters",
bounded_ty.repr(tcx)).as_slice()) bounded_ty.repr(tcx))
} }
fn is_ty_param(ty: ty::Ty) -> bool { fn is_ty_param(ty: ty::Ty) -> bool {
@ -326,10 +324,9 @@ fn reject_shadowing_type_parameters<'tcx>(tcx: &ty::ctxt<'tcx>,
for method_param in generics.types.get_slice(subst::FnSpace).iter() { for method_param in generics.types.get_slice(subst::FnSpace).iter() {
if impl_params.contains(&method_param.name) { if impl_params.contains(&method_param.name) {
tcx.sess.span_err( span_err!(tcx.sess, span, E0194,
span, "type parameter `{}` shadows another type parameter of the same name",
&*format!("type parameter `{}` shadows another type parameter of the same name", token::get_name(method_param.name));
token::get_name(method_param.name)));
} }
} }
} }

View File

@ -416,7 +416,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
ResolvingUnboxedClosure(_) => { ResolvingUnboxedClosure(_) => {
let span = self.reason.span(self.tcx); let span = self.reason.span(self.tcx);
self.tcx.sess.span_err(span, span_err!(self.tcx.sess, span, E0196,
"cannot determine a type for this \ "cannot determine a type for this \
unboxed closure") unboxed closure")
} }

View File

@ -34,10 +34,9 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for ImplsChecker<'cx, 'tcx> {
match trait_ref.self_ty().sty { match trait_ref.self_ty().sty {
ty::ty_struct(..) | ty::ty_enum(..) => {} ty::ty_struct(..) | ty::ty_enum(..) => {}
_ => { _ => {
self.tcx.sess.span_err( span_err!(self.tcx.sess, item.span, E0209,
item.span, "builtin traits can only be \
&format!("builtin traits can only be \ implemented on structs or enums");
implemented on structs or enums")[]);
} }
} }
} }

View File

@ -490,24 +490,21 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
match ty::can_type_implement_copy(&param_env, span, self_type) { match ty::can_type_implement_copy(&param_env, span, self_type) {
Ok(()) => {} Ok(()) => {}
Err(ty::FieldDoesNotImplementCopy(name)) => { Err(ty::FieldDoesNotImplementCopy(name)) => {
tcx.sess span_err!(tcx.sess, span, E0204,
.span_err(span, "the trait `Copy` may not be \
&format!("the trait `Copy` may not be \
implemented for this type; field \ implemented for this type; field \
`{}` does not implement `Copy`", `{}` does not implement `Copy`",
token::get_name(name))[]) token::get_name(name))
} }
Err(ty::VariantDoesNotImplementCopy(name)) => { Err(ty::VariantDoesNotImplementCopy(name)) => {
tcx.sess span_err!(tcx.sess, span, E0205,
.span_err(span, "the trait `Copy` may not be \
&format!("the trait `Copy` may not be \
implemented for this type; variant \ implemented for this type; variant \
`{}` does not implement `Copy`", `{}` does not implement `Copy`",
token::get_name(name))[]) token::get_name(name))
} }
Err(ty::TypeIsStructural) => { Err(ty::TypeIsStructural) => {
tcx.sess span_err!(tcx.sess, span, E0206,
.span_err(span,
"the trait `Copy` may not be implemented \ "the trait `Copy` may not be implemented \
for this type; type is not a structure or \ for this type; type is not a structure or \
enumeration") enumeration")

View File

@ -89,13 +89,11 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
} }
Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => { Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {
if !ty::has_attr(self.tcx, trait_def_id, "old_orphan_check") { if !ty::has_attr(self.tcx, trait_def_id, "old_orphan_check") {
self.tcx.sess.span_err( span_err!(self.tcx.sess, item.span, E0210,
item.span,
format!(
"type parameter `{}` is not constrained by any local type; \ "type parameter `{}` is not constrained by any local type; \
only traits defined in the current crate can be implemented \ only traits defined in the current crate can be implemented \
for a type parameter", for a type parameter",
param_ty.user_string(self.tcx)).as_slice()); param_ty.user_string(self.tcx));
self.tcx.sess.span_note( self.tcx.sess.span_note(
item.span, item.span,
format!("for a limited time, you can add \ format!("for a limited time, you can add \

View File

@ -37,8 +37,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
match unsafety { match unsafety {
ast::Unsafety::Normal => { /* OK */ } ast::Unsafety::Normal => { /* OK */ }
ast::Unsafety::Unsafe => { ast::Unsafety::Unsafe => {
self.tcx.sess.span_err( span_err!(self.tcx.sess, item.span, E0197,
item.span,
"inherent impls cannot be declared as unsafe"); "inherent impls cannot be declared as unsafe");
} }
} }
@ -49,24 +48,21 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
match (trait_def.unsafety, unsafety, polarity) { match (trait_def.unsafety, unsafety, polarity) {
(ast::Unsafety::Unsafe, (ast::Unsafety::Unsafe,
ast::Unsafety::Unsafe, ast::ImplPolarity::Negative) => { ast::Unsafety::Unsafe, ast::ImplPolarity::Negative) => {
self.tcx.sess.span_err( span_err!(self.tcx.sess, item.span, E0198,
item.span, "negative implementations are not unsafe");
format!("negative implementations are not unsafe").as_slice());
} }
(ast::Unsafety::Normal, ast::Unsafety::Unsafe, _) => { (ast::Unsafety::Normal, ast::Unsafety::Unsafe, _) => {
self.tcx.sess.span_err( span_err!(self.tcx.sess, item.span, E0199,
item.span, "implementing the trait `{}` is not unsafe",
format!("implementing the trait `{}` is not unsafe", trait_ref.user_string(self.tcx));
trait_ref.user_string(self.tcx)).as_slice());
} }
(ast::Unsafety::Unsafe, (ast::Unsafety::Unsafe,
ast::Unsafety::Normal, ast::ImplPolarity::Positive) => { ast::Unsafety::Normal, ast::ImplPolarity::Positive) => {
self.tcx.sess.span_err( span_err!(self.tcx.sess, item.span, E0200,
item.span, "the trait `{}` requires an `unsafe impl` declaration",
format!("the trait `{}` requires an `unsafe impl` declaration", trait_ref.user_string(self.tcx));
trait_ref.user_string(self.tcx)).as_slice());
} }
(ast::Unsafety::Unsafe, (ast::Unsafety::Unsafe,

View File

@ -452,7 +452,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>,
let mut seen_methods = FnvHashSet(); let mut seen_methods = FnvHashSet();
for m in ms { for m in ms {
if !seen_methods.insert(m.pe_ident().repr(tcx)) { if !seen_methods.insert(m.pe_ident().repr(tcx)) {
tcx.sess.span_err(m.span, "duplicate method in trait impl"); span_err!(tcx.sess, m.span, E0201, "duplicate method in trait impl");
} }
let m_def_id = local_def(m.id); let m_def_id = local_def(m.id);
@ -608,7 +608,7 @@ fn convert(ccx: &CollectCtxt, it: &ast::Item) {
} }
ast::TypeImplItem(ref typedef) => { ast::TypeImplItem(ref typedef) => {
if opt_trait_ref.is_none() { if opt_trait_ref.is_none() {
tcx.sess.span_err(typedef.span, span_err!(tcx.sess, typedef.span, E0202,
"associated items are not allowed in inherent impls"); "associated items are not allowed in inherent impls");
} }
@ -1160,7 +1160,8 @@ fn add_unsized_bound<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
assert!(ptr.bound_lifetimes.is_empty()); assert!(ptr.bound_lifetimes.is_empty());
unbound = Some(ptr.trait_ref.clone()); unbound = Some(ptr.trait_ref.clone());
} else { } else {
ccx.tcx.sess.span_err(span, "type parameter has more than one relaxed default \ span_err!(ccx.tcx.sess, span, E0203,
"type parameter has more than one relaxed default \
bound, only one is supported"); bound, only one is supported");
} }
} }
@ -1690,11 +1691,10 @@ fn enforce_impl_ty_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
impl trait, self type, or predicates", impl trait, self type, or predicates",
param_ty.user_string(tcx)).as_slice()); param_ty.user_string(tcx)).as_slice());
} else { } else {
tcx.sess.span_err( span_err!(tcx.sess, ty_param.span, E0207,
ty_param.span, "the type parameter `{}` is not constrained by the \
format!("the type parameter `{}` is not constrained by the \
impl trait, self type, or predicates", impl trait, self type, or predicates",
param_ty.user_string(tcx)).as_slice()); param_ty.user_string(tcx));
tcx.sess.span_help( tcx.sess.span_help(
ty_param.span, ty_param.span,
format!("you can temporarily opt out of this rule by placing \ format!("you can temporarily opt out of this rule by placing \

View File

@ -10,38 +10,7 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
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.
"## }
register_diagnostics! { register_diagnostics! {
E0002,
E0003,
E0004,
E0005,
E0006,
E0007,
E0008,
E0009,
E0010,
E0011,
E0012,
E0013,
E0014,
E0015,
E0016,
E0017,
E0018,
E0019,
E0020,
E0022,
E0023, E0023,
E0024, E0024,
E0025, E0025,
@ -61,12 +30,9 @@ register_diagnostics! {
E0046, E0046,
E0049, E0049,
E0050, E0050,
E0051,
E0052,
E0053, E0053,
E0054, E0054,
E0055, E0055,
E0056,
E0057, E0057,
E0059, E0059,
E0060, E0060,
@ -101,16 +67,12 @@ register_diagnostics! {
E0092, E0092,
E0093, E0093,
E0094, E0094,
E0100,
E0101, E0101,
E0102, E0102,
E0103, E0103,
E0104, E0104,
E0106, E0106,
E0107, E0107,
E0108,
E0109,
E0110,
E0116, E0116,
E0117, E0117,
E0118, E0118,
@ -125,38 +87,92 @@ register_diagnostics! {
E0130, E0130,
E0131, E0131,
E0132, E0132,
E0133,
E0134,
E0135,
E0136,
E0137,
E0138,
E0139,
E0140,
E0141, E0141,
E0152,
E0153,
E0157,
E0158,
E0159, E0159,
E0161,
E0162,
E0163, E0163,
E0164, E0164,
E0165,
E0166, E0166,
E0167, E0167,
E0168, E0168,
E0169,
E0171,
E0172, E0172,
E0173, // manual implementations of unboxed closure traits are experimental E0173, // manual implementations of unboxed closure traits are experimental
E0174, // explicit use of unboxed closure methods are experimental E0174, // explicit use of unboxed closure methods are experimental
E0177,
E0178, E0178,
E0180,
E0181,
E0182, E0182,
E0183, E0183,
E0184 E0184,
E0185,
E0186,
E0187, // can't infer the kind of the closure
E0188, // types differ in mutability
E0189, // can only cast a boxed pointer to a boxed object
E0190, // can only cast a &-pointer to an &-object
E0191, // value of the associated type must be specified
E0192, // negative imples are allowed just fo `Send` and `Sync`
E0193, // cannot bound type where clause bounds may only be attached to types
// involving type parameters
E0194,
E0195, // lifetime parameters or bounds on method do not match the trait declaration
E0196, // cannot determine a type for this unboxed closure
E0197, // inherent impls cannot be declared as unsafe
E0198, // negative implementations are not unsafe
E0199, // implementing trait is not unsafe
E0200, // trait requires an `unsafe impl` declaration
E0201, // duplicate method in trait impl
E0202, // associated items are not allowed in inherint impls
E0203, // type parameter has more than one relaxed default bound,
// and only one is supported
E0204, // trait `Copy` may not be implemented for this type; field
// does not implement `Copy`
E0205, // trait `Copy` may not be implemented for this type; variant
// does not implement `copy`
E0206, // trait `Copy` may not be implemented for this type; type is
// not a structure or enumeration
E0207, // type parameter is not constrained by the impl trait, self type, or predicate
E0208,
E0209, // builtin traits can only be implemented on structs or enums
E0210, // type parameter is not constrained by any local type
E0211,
E0212, // cannot extract an associated type from a higher-ranked trait bound
E0213, // associated types are not accepted in this context
E0214, // parenthesized parameters may only be used with a trait
E0215, // angle-bracket notation is not stable with `Fn`
E0216, // parenthetical notation is only stable with `Fn`
E0217, // ambiguous associated type, defined in multiple supertraits
E0218, // no associated type defined
E0219, // associated type defined in higher-ranked supertrait
E0220, // associated type not found for type parameter
E0221, // ambiguous associated type in bounds
E0222, // variadic function must have C calling convention
E0223, // ambiguous associated type
E0224, // at least one non-builtin train is required for an object type
E0225, // only the builtin traits can be used as closure or object bounds
E0226, // only a single explicit lifetime bound is permitted
E0227, // ambiguous lifetime bound, explicit lifetime bound required
E0228, // explicit lifetime bound required
E0229, // associated type bindings are not allowed here
E0230, // there is no type parameter on trait
E0231, // only named substitution parameters are allowed
E0232, // this attribute must have a value
E0233,
E0234, // `for` loop expression has type which does not implement the `Iterator` trait
E0235, // structure constructor specifies a structure of type but
E0236, // no lang item for range syntax
E0237, // no lang item for range syntax
E0238, // parenthesized parameters may only be used with a trait
E0239, // `next` method of `Iterator` trait has unexpected type
E0240,
E0241,
E0242, // internal error looking up a definition
E0243, // wrong number of type arguments
E0244, // wrong number of type arguments
E0245, // not a trait
E0246, // illegal recursive type
E0247, // found module name used as a type
E0248, // found value name used as a type
E0249, // expected constant expr for array length
E0250 // expected constant expr for array length
} }
__build_diagnostic_array! { DIAGNOSTICS }

View File

@ -111,6 +111,10 @@ use syntax::ast_util::local_def;
use std::cell::RefCell; use std::cell::RefCell;
// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;
mod check; mod check;
mod rscope; mod rscope;
mod astconv; mod astconv;
@ -158,7 +162,7 @@ fn lookup_def_tcx(tcx:&ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def {
match tcx.def_map.borrow().get(&id) { match tcx.def_map.borrow().get(&id) {
Some(x) => x.clone(), Some(x) => x.clone(),
_ => { _ => {
tcx.sess.span_fatal(sp, "internal error looking up a definition") span_fatal!(tcx.sess, sp, E0242, "internal error looking up a definition")
} }
} }
} }
@ -202,11 +206,11 @@ fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>,
match result { match result {
Ok(_) => true, Ok(_) => true,
Err(ref terr) => { Err(ref terr) => {
tcx.sess.span_err(span, span_err!(tcx.sess, span, E0211,
&format!("{}: {}", "{}: {}",
msg(), msg(),
ty::type_err_to_str(tcx, ty::type_err_to_str(tcx,
terr))[]); terr));
ty::note_and_explain_type_err(tcx, terr); ty::note_and_explain_type_err(tcx, terr);
false false
} }

View File

@ -1055,7 +1055,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
// attribute and report an error with various results if found. // attribute and report an error with various results if found.
if ty::has_attr(tcx, item_def_id, "rustc_variance") { if ty::has_attr(tcx, item_def_id, "rustc_variance") {
let found = item_variances.repr(tcx); let found = item_variances.repr(tcx);
tcx.sess.span_err(tcx.map.span(item_id), &found[]); span_err!(tcx.sess, tcx.map.span(item_id), E0208, "{}", &found[]);
} }
let newly_added = tcx.item_variance_map.borrow_mut() let newly_added = tcx.item_variance_map.borrow_mut()

View File

@ -92,6 +92,10 @@ impl SpanHandler {
self.handler.emit(Some((&self.cm, sp)), msg, Fatal); self.handler.emit(Some((&self.cm, sp)), msg, Fatal);
panic!(FatalError); panic!(FatalError);
} }
pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> ! {
self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Fatal);
panic!(FatalError);
}
pub fn span_err(&self, sp: Span, msg: &str) { pub fn span_err(&self, sp: Span, msg: &str) {
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();

View File

@ -14,6 +14,14 @@ macro_rules! register_diagnostic {
($code:tt) => (__register_diagnostic! { $code }) ($code:tt) => (__register_diagnostic! { $code })
} }
#[macro_export]
macro_rules! span_fatal {
($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
$session.span_fatal_with_code($span, format!($($message)*).as_slice(), stringify!($code))
})
}
#[macro_export] #[macro_export]
macro_rules! span_err { macro_rules! span_err {
($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
@ -51,3 +59,9 @@ macro_rules! register_diagnostics {
) )
} }
#[macro_export]
macro_rules! register_long_diagnostics {
($($code:tt: $description:tt),*) => (
$(register_diagnostic! { $code, $description })*
)
}

View File

@ -65,6 +65,13 @@ pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt,
} }
() ()
}); });
with_registered_diagnostics(|diagnostics| {
if !diagnostics.contains_key(&code.name) {
ecx.span_err(span, &format!(
"used diagnostic code {} not registered", token::get_ident(code).get()
)[]);
}
});
MacExpr::new(quote_expr!(ecx, ())) MacExpr::new(quote_expr!(ecx, ()))
} }

View File

@ -44,7 +44,7 @@ fn basic_sess(sysroot: Path) -> Session {
opts.output_types = vec![OutputTypeExe]; opts.output_types = vec![OutputTypeExe];
opts.maybe_sysroot = Some(sysroot); opts.maybe_sysroot = Some(sysroot);
let descriptions = Registry::new(&rustc::DIAGNOSTICS); let descriptions = Registry::new(&rustc::diagnostics::DIAGNOSTICS);
let sess = build_session(opts, None, descriptions); let sess = build_session(opts, None, descriptions);
sess sess
} }