Convert a first batch of diagnostics to have error codes

This commit is contained in:
Jakub Wieczorek 2014-07-11 18:54:01 +02:00
parent 350f3aa856
commit a5fe176e97
11 changed files with 410 additions and 390 deletions

View File

@ -16,3 +16,99 @@ register_diagnostic!(E0001, r##"
This means that perhaps some of the preceeding patterns are too general, this
one is too specific or the ordering is incorrect.
"##)
register_diagnostics!(
E0002,
E0003,
E0004,
E0005,
E0006,
E0007,
E0008,
E0009,
E0010,
E0011,
E0012,
E0013,
E0014,
E0015,
E0016,
E0017,
E0018,
E0019,
E0020,
E0021,
E0022,
E0023,
E0024,
E0025,
E0026,
E0027,
E0028,
E0029,
E0030,
E0031,
E0032,
E0033,
E0034,
E0035,
E0036,
E0037,
E0038,
E0039,
E0040,
E0041,
E0042,
E0043,
E0044,
E0045,
E0046,
E0047,
E0048,
E0049,
E0050,
E0051,
E0052,
E0053,
E0054,
E0055,
E0056,
E0057,
E0058,
E0059,
E0060,
E0061,
E0062,
E0063,
E0064,
E0065,
E0066,
E0067,
E0068,
E0069,
E0070,
E0071,
E0072,
E0073,
E0074,
E0075,
E0076,
E0077,
E0078,
E0079,
E0080,
E0081,
E0082,
E0083,
E0084,
E0085,
E0086,
E0087,
E0088,
E0089,
E0090,
E0091,
E0092,
E0093,
E0094
)

View File

@ -85,6 +85,9 @@ impl Session {
pub fn span_warn(&self, sp: Span, msg: &str) {
self.diagnostic().span_warn(sp, msg)
}
pub fn span_warn_with_code(&self, sp: Span, msg: &str, code: &str) {
self.diagnostic().span_warn_with_code(sp, msg, code)
}
pub fn warn(&self, msg: &str) {
self.diagnostic().handler().warn(msg)
}

View File

@ -87,28 +87,25 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) {
match e.node {
ExprUnary(UnDeref, _) => { }
ExprUnary(UnBox, _) | ExprUnary(UnUniq, _) => {
v.tcx.sess.span_err(e.span,
"cannot do allocations in constant expressions");
span_err!(v.tcx.sess, e.span, E0010, "cannot do allocations in constant expressions");
return;
}
ExprLit(lit) if ast_util::lit_is_str(lit) => {}
ExprBinary(..) | ExprUnary(..) => {
let method_call = typeck::MethodCall::expr(e.id);
if v.tcx.method_map.borrow().contains_key(&method_call) {
v.tcx.sess.span_err(e.span, "user-defined operators are not \
allowed in constant expressions");
span_err!(v.tcx.sess, e.span, E0011,
"user-defined operators are not allowed in constant expressions");
}
}
ExprLit(_) => (),
ExprCast(_, _) => {
let ety = ty::expr_ty(v.tcx, e);
if !ty::type_is_numeric(ety) && !ty::type_is_unsafe_ptr(ety) {
v.tcx
.sess
.span_err(e.span,
format!("can not cast to `{}` in a constant \
expression",
ppaux::ty_to_string(v.tcx, ety)).as_slice())
span_err!(v.tcx.sess, e.span, E0012,
"can not cast to `{}` in a constant expression",
ppaux::ty_to_string(v.tcx, ety)
);
}
}
ExprPath(ref pth) => {
@ -117,9 +114,8 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) {
// foo::<bar> in a const. Currently that is only done on
// a path in trans::callee that only works in block contexts.
if !pth.segments.iter().all(|segment| segment.types.is_empty()) {
v.tcx.sess.span_err(e.span,
"paths in constants may only refer to \
items without type parameters");
span_err!(v.tcx.sess, e.span, E0013,
"paths in constants may only refer to items without type parameters");
}
match v.tcx.def_map.borrow().find(&e.id) {
Some(&DefStatic(..)) |
@ -129,9 +125,8 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) {
Some(&def) => {
debug!("(checking const) found bad def: {:?}", def);
v.tcx.sess.span_err(e.span,
"paths in constants may only refer to \
constants or functions");
span_err!(v.tcx.sess, e.span, E0014,
"paths in constants may only refer to constants or functions");
}
None => {
v.tcx.sess.span_bug(e.span, "unbound path in const?!");
@ -143,9 +138,8 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) {
Some(&DefStruct(..)) => {} // OK.
Some(&DefVariant(..)) => {} // OK.
_ => {
v.tcx.sess.span_err(e.span,
"function calls in constants are limited to \
struct and enum constructors");
span_err!(v.tcx.sess, e.span, E0015,
"function calls in constants are limited to struct and enum constructors");
}
}
}
@ -153,9 +147,8 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) {
// Check all statements in the block
for stmt in block.stmts.iter() {
let block_span_err = |span|
v.tcx.sess.span_err(span,
"blocks in constants are limited to \
items and tail expressions");
span_err!(v.tcx.sess, span, E0016,
"blocks in constants are limited to items and tail expressions");
match stmt.node {
StmtDecl(ref span, _) => {
match span.node {
@ -187,18 +180,18 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) {
ExprRepeat(..) |
ExprStruct(..) => { }
ExprAddrOf(..) => {
v.tcx.sess.span_err(e.span,
"references in constants may only refer to \
immutable values");
span_err!(v.tcx.sess, e.span, E0017,
"references in constants may only refer to immutable values");
},
ExprVstore(_, ExprVstoreUniq) => {
v.tcx.sess.span_err(e.span, "cannot allocate vectors in constant expressions")
span_err!(v.tcx.sess, e.span, E0018,
"cannot allocate vectors in constant expressions");
},
_ => {
v.tcx.sess.span_err(e.span,
"constant contains unimplemented expression type");
return;
span_err!(v.tcx.sess, e.span, E0019,
"constant contains unimplemented expression type");
return;
}
}
}

View File

@ -142,15 +142,16 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
// Finally, check if the whole match expression is exhaustive.
// Check for empty enum, because is_useful only works on inhabited types.
let pat_ty = node_id_to_type(cx.tcx, scrut.id);
if (*arms).is_empty() {
if !type_is_empty(cx.tcx, pat_ty) {
// We know the type is inhabited, so this must be wrong
cx.tcx.sess.span_err(ex.span, format!("non-exhaustive patterns: \
type {} is non-empty",
ty_to_string(cx.tcx, pat_ty)).as_slice());
}
// If the type *is* empty, it's vacuously exhaustive
return;
if arms.is_empty() {
if !type_is_empty(cx.tcx, pat_ty) {
// We know the type is inhabited, so this must be wrong
span_err!(cx.tcx.sess, ex.span, E0002,
"non-exhaustive patterns: type {} is non-empty",
ty_to_string(cx.tcx, pat_ty)
);
}
// If the type *is* empty, it's vacuously exhaustive
return;
}
let m: Matrix = Matrix(arms
.iter()
@ -186,8 +187,9 @@ fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) {
walk_pat(&**pat, |p| {
if pat_matches_nan(p) {
cx.tcx.sess.span_warn(p.span, "unmatchable NaN in pattern, \
use the is_nan method in a guard instead");
span_warn!(cx.tcx.sess, p.span, E0003,
"unmatchable NaN in pattern, use the is_nan method in a guard instead"
);
}
true
});
@ -222,9 +224,10 @@ fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &Matrix) {
[] => wild(),
_ => unreachable!()
};
let msg = format!("non-exhaustive patterns: `{0}` not covered",
pat_to_string(&*witness));
cx.tcx.sess.span_err(sp, msg.as_slice());
span_err!(cx.tcx.sess, sp, E0004,
"non-exhaustive patterns: `{}` not covered",
pat_to_string(&*witness)
);
}
NotUseful => {
// This is good, wildcard pattern isn't reachable
@ -779,11 +782,10 @@ fn check_local(cx: &mut MatchCheckCtxt, loc: &Local) {
match is_refutable(cx, loc.pat) {
Some(pat) => {
let msg = format!(
span_err!(cx.tcx.sess, loc.pat.span, E0005,
"refutable pattern in {} binding: `{}` not covered",
name, pat_to_string(&*pat)
);
cx.tcx.sess.span_err(loc.pat.span, msg.as_slice());
},
None => ()
}
@ -801,11 +803,10 @@ fn check_fn(cx: &mut MatchCheckCtxt,
for input in decl.inputs.iter() {
match is_refutable(cx, input.pat) {
Some(pat) => {
let msg = format!(
span_err!(cx.tcx.sess, input.pat.span, E0006,
"refutable pattern in function argument: `{}` not covered",
pat_to_string(&*pat)
);
cx.tcx.sess.span_err(input.pat.span, msg.as_slice());
},
None => ()
}
@ -850,21 +851,13 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
// x @ Foo(..) is legal, but x @ Foo(y) isn't.
if sub.map_or(false, |p| pat_contains_bindings(def_map, &*p)) {
tcx.sess.span_err(
p.span,
"cannot bind by-move with sub-bindings");
span_err!(cx.tcx.sess, p.span, E0007, "cannot bind by-move with sub-bindings");
} else if has_guard {
tcx.sess.span_err(
p.span,
"cannot bind by-move into a pattern guard");
span_err!(cx.tcx.sess, p.span, E0008, "cannot bind by-move into a pattern guard");
} else if by_ref_span.is_some() {
tcx.sess.span_err(
p.span,
"cannot bind by-move and by-ref \
in the same pattern");
tcx.sess.span_note(
by_ref_span.unwrap(),
"by-ref binding occurs here");
span_err!(cx.tcx.sess, p.span, E0009,
"cannot bind by-move and by-ref in the same pattern");
span_note!(cx.tcx.sess, by_ref_span.unwrap(), "by-ref binding occurs here");
}
};

View File

@ -112,18 +112,18 @@ impl<'a> Visitor<bool> for CheckStaticVisitor<'a> {
visit::walk_expr(self, e, is_const);
}
ast::ExprVstore(_, ast::ExprVstoreMutSlice) => {
self.tcx.sess.span_err(e.span,
"static items are not allowed to have mutable slices");
span_err!(self.tcx.sess, e.span, E0020,
"static items are not allowed to have mutable slices");
},
ast::ExprUnary(ast::UnBox, _) => {
self.tcx.sess.span_err(e.span,
"static items are not allowed to have managed pointers");
span_err!(self.tcx.sess, e.span, E0021,
"static items are not allowed to have managed pointers");
}
ast::ExprBox(..) |
ast::ExprUnary(ast::UnUniq, _) |
ast::ExprVstore(_, ast::ExprVstoreUniq) => {
self.tcx.sess.span_err(e.span,
"static items are not allowed to have custom pointers");
span_err!(self.tcx.sess, e.span, E0022,
"static items are not allowed to have custom pointers");
}
_ => {
let node_ty = ty::node_id_to_type(self.tcx, e.id);

View File

@ -253,14 +253,10 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: &ast::Pat, path: &ast::Path,
if arg_len > 0 {
// N-ary variant.
if arg_len != subpats_len {
let s = format!("this pattern has {} field{}, \
but the corresponding {} has {} field{}",
subpats_len,
if subpats_len == 1 {""} else {"s"},
kind_name,
arg_len,
if arg_len == 1 {""} else {"s"});
tcx.sess.span_err(pat.span, s.as_slice());
span_err!(tcx.sess, pat.span, E0023,
"this pattern has {} field{}, but the corresponding {} has {} field{}",
subpats_len, if subpats_len == 1 {""} else {"s"},
kind_name, arg_len, if arg_len == 1 {""} else {"s"});
error_happened = true;
}
@ -272,12 +268,10 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: &ast::Pat, path: &ast::Path,
}
}
} else if subpats_len > 0 {
tcx.sess.span_err(pat.span,
format!("this pattern has {} field{}, \
but the corresponding {} has no fields",
subpats_len,
if subpats_len == 1 {""} else {"s"},
kind_name).as_slice());
span_err!(tcx.sess, pat.span, E0024,
"this pattern has {} field{}, but the corresponding {} has no fields",
subpats_len, if subpats_len == 1 {""} else {"s"},
kind_name);
error_happened = true;
}
@ -321,9 +315,9 @@ pub fn check_struct_pat_fields(pcx: &pat_ctxt,
// Check the pattern anyway, so that attempts to look
// up its type won't fail
check_pat(pcx, &*field.pat, ty::mk_err());
tcx.sess.span_err(span,
format!("field `{}` bound twice in pattern",
token::get_ident(field.ident)).as_slice());
span_err!(tcx.sess, span, E0025,
"field `{}` bound twice in pattern",
token::get_ident(field.ident));
}
Some(&(index, ref mut used)) => {
*used = true;
@ -339,10 +333,10 @@ pub fn check_struct_pat_fields(pcx: &pat_ctxt,
// Check the pattern anyway, so that attempts to look
// up its type won't fail
check_pat(pcx, &*field.pat, ty::mk_err());
tcx.sess.span_err(span,
format!("struct `{}` does not have a field named `{}`",
ty::item_path_str(tcx, class_id),
token::get_ident(field.ident)).as_slice());
span_err!(tcx.sess, span, E0026,
"struct `{}` does not have a field named `{}`",
ty::item_path_str(tcx, class_id),
token::get_ident(field.ident));
}
}
}
@ -353,11 +347,9 @@ pub fn check_struct_pat_fields(pcx: &pat_ctxt,
if found_fields.contains(&i) {
continue;
}
tcx.sess
.span_err(span,
format!("pattern does not mention field `{}`",
token::get_name(field.name)).as_slice());
span_err!(tcx.sess, span, E0027,
"pattern does not mention field `{}`",
token::get_name(field.name));
}
}
}
@ -400,11 +392,9 @@ pub fn check_struct_like_enum_variant_pat(pcx: &pat_ctxt,
}
Some(&def::DefStruct(..)) | Some(&def::DefVariant(..)) => {
let name = pprust::path_to_string(path);
tcx.sess.span_err(span,
format!("mismatched types: expected `{}` but \
found `{}`",
fcx.infcx().ty_to_string(expected),
name).as_slice());
span_err!(tcx.sess, span, E0028,
"mismatched types: expected `{}` but found `{}`",
fcx.infcx().ty_to_string(expected), name);
}
_ => {
tcx.sess.span_bug(span, "resolve didn't write in variant");
@ -441,16 +431,16 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
{
// no-op
} else if !ty::type_is_numeric(b_ty) && !ty::type_is_char(b_ty) {
tcx.sess.span_err(pat.span,
span_err!(tcx.sess, begin.span, E0029,
"only char and numeric types are allowed in range");
} else {
match valid_range_bounds(fcx.ccx, &**begin, &**end) {
Some(false) => {
tcx.sess.span_err(begin.span,
span_err!(tcx.sess, begin.span, E0030,
"lower range bound must be less than upper");
},
None => {
tcx.sess.span_err(begin.span,
span_err!(tcx.sess, begin.span, E0031,
"mismatched types in range");
},
_ => { },
@ -521,13 +511,10 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
ty::ty_to_def_id(
ty::lookup_item_type(tcx, item_did).ty).unwrap();
if struct_did != cid {
tcx.sess
.span_err(path.span,
format!("`{}` does not name the \
structure `{}`",
pprust::path_to_string(path),
fcx.infcx()
.ty_to_string(expected)).as_slice())
span_err!(tcx.sess, pat.span, E0032,
"`{}` does not name the structure `{}`",
pprust::path_to_string(path),
fcx.infcx().ty_to_string(expected));
}
check_struct_pat(pcx, pat.id, pat.span, expected, path,
@ -744,10 +731,9 @@ fn check_pointer_pat(pcx: &pat_ctxt,
// This is "x = SomeTrait" being reduced from
// "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
check_pat(pcx, inner, ty::mk_err());
tcx.sess.span_err(
span,
format!("type `{}` cannot be dereferenced",
fcx.infcx().ty_to_string(expected)).as_slice());
span_err!(tcx.sess, span, E0033,
"type `{}` cannot be dereferenced",
fcx.infcx().ty_to_string(expected));
fcx.write_error(pat_id);
}
_ => {

View File

@ -1041,8 +1041,7 @@ impl<'a> LookupContext<'a> {
}
if relevant_candidates.len() > 1 {
self.tcx().sess.span_err(
self.span,
span_err!(self.tcx().sess, self.span, E0034,
"multiple applicable methods in scope");
for (idx, candidate) in relevant_candidates.iter().enumerate() {
self.report_candidate(idx, &candidate.origin);
@ -1112,13 +1111,11 @@ impl<'a> LookupContext<'a> {
if num_supplied_tps == 0u {
self.fcx.infcx().next_ty_vars(num_method_tps)
} else if num_method_tps == 0u {
tcx.sess.span_err(
self.span,
"this method does not take type parameters");
span_err!(tcx.sess, self.span, E0035,
"does not take type parameters");
self.fcx.infcx().next_ty_vars(num_method_tps)
} else if num_supplied_tps != num_method_tps {
tcx.sess.span_err(
self.span,
span_err!(tcx.sess, self.span, E0036,
"incorrect number of type parameters given for this method");
self.fcx.infcx().next_ty_vars(num_method_tps)
} else {
@ -1221,10 +1218,8 @@ impl<'a> LookupContext<'a> {
match candidate.method_ty.explicit_self {
ast::SelfStatic => { // reason (a) above
self.tcx().sess.span_err(
self.span,
"cannot call a method without a receiver \
through an object");
span_err!(self.tcx().sess, self.span, E0037,
"cannot call a method without a receiver through an object");
}
ast::SelfValue(_) | ast::SelfRegion(..) | ast::SelfUniq(_) => {}
@ -1233,8 +1228,7 @@ impl<'a> LookupContext<'a> {
// reason (a) above
let check_for_self_ty = |ty| {
if ty::type_has_self(ty) {
self.tcx().sess.span_err(
self.span,
span_err!(self.tcx().sess, self.span, E0038,
"cannot call a method whose type contains a \
self-type through an object");
true
@ -1256,8 +1250,7 @@ impl<'a> LookupContext<'a> {
if candidate.method_ty.generics.has_type_params(subst::FnSpace) {
// reason (b) above
self.tcx().sess.span_err(
self.span,
span_err!(self.tcx().sess, self.span, E0039,
"cannot call a generic method through an object");
}
}
@ -1279,8 +1272,8 @@ impl<'a> LookupContext<'a> {
}
if bad {
self.tcx().sess.span_err(self.span,
"explicit call to destructor");
span_err!(self.tcx().sess, self.span, E0040,
"explicit call to destructor");
}
}
@ -1425,28 +1418,22 @@ impl<'a> LookupContext<'a> {
} else {
self.span
};
self.tcx().sess.span_note(
span,
format!("candidate #{} is `{}`",
idx + 1u,
ty::item_path_str(self.tcx(), did)).as_slice());
span_note!(self.tcx().sess, span,
"candidate #{} is `{}`",
idx + 1u, ty::item_path_str(self.tcx(), did));
}
fn report_param_candidate(&self, idx: uint, did: DefId) {
self.tcx().sess.span_note(
self.span,
format!("candidate #{} derives from the bound `{}`",
idx + 1u,
ty::item_path_str(self.tcx(), did)).as_slice());
span_note!(self.tcx().sess, self.span,
"candidate #{} derives from the bound `{}`",
idx + 1u, ty::item_path_str(self.tcx(), did));
}
fn report_trait_candidate(&self, idx: uint, did: DefId) {
self.tcx().sess.span_note(
self.span,
format!("candidate #{} derives from the type of the receiver, \
which is the trait `{}`",
idx + 1u,
ty::item_path_str(self.tcx(), did)).as_slice());
span_note!(self.tcx().sess, self.span,
"candidate #{} derives from the type of the receiver, \
which is the trait `{}`",
idx + 1u, ty::item_path_str(self.tcx(), did));
}
fn infcx(&'a self) -> &'a infer::InferCtxt<'a> {

View File

@ -569,11 +569,10 @@ fn check_for_field_shadowing(tcx: &ty::ctxt,
for f in fields.iter() {
match super_fields.iter().find(|sf| f.name == sf.name) {
Some(prev_field) => {
tcx.sess.span_err(span_for_field(tcx, f, id),
format!("field `{}` hides field declared in \
super-struct",
token::get_name(f.name)).as_slice());
tcx.sess.span_note(span_for_field(tcx, prev_field, parent_id),
span_err!(tcx.sess, span_for_field(tcx, f, id), E0041,
"field `{}` hides field declared in super-struct",
token::get_name(f.name));
span_note!(tcx.sess, span_for_field(tcx, prev_field, parent_id),
"previously declared here");
},
None => {}
@ -595,16 +594,16 @@ fn check_fields_sized(tcx: &ty::ctxt,
if !ty::type_is_sized(tcx, t) {
match f.node.kind {
ast::NamedField(ident, _) => {
tcx.sess.span_err(
f.span,
format!("type `{}` is dynamically sized. \
dynamically sized types may only \
appear as the type of the final \
field in a struct",
token::get_ident(ident)).as_slice());
span_err!(tcx.sess, f.span, E0042,
"type `{}` is dynamically sized. \
dynamically sized types may only \
appear as the type of the final \
field in a struct",
token::get_ident(ident));
}
ast::UnnamedField(_) => {
tcx.sess.span_err(f.span, "dynamically sized type in field");
span_err!(tcx.sess, f.span, E0043,
"dynamically sized type in field");
}
}
}
@ -719,14 +718,15 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
for item in m.items.iter() {
let pty = ty::lookup_item_type(ccx.tcx, local_def(item.id));
if !pty.generics.types.is_empty() {
ccx.tcx.sess.span_err(item.span, "foreign items may not have type parameters");
span_err!(ccx.tcx.sess, item.span, E0044,
"foreign items may not have type parameters");
}
match item.node {
ast::ForeignItemFn(ref fn_decl, _) => {
if fn_decl.variadic && m.abi != abi::C {
ccx.tcx.sess.span_err(
item.span, "variadic function must have C calling convention");
span_err!(ccx.tcx.sess, item.span, E0045,
"variadic function must have C calling convention");
}
}
_ => {}
@ -826,10 +826,9 @@ fn check_impl_methods_against_trait(ccx: &CrateCtxt,
}
if !missing_methods.is_empty() {
tcx.sess.span_err(
impl_span,
format!("not all trait methods implemented, missing: {}",
missing_methods.connect(", ")).as_slice());
span_err!(tcx.sess, impl_span, E0046,
"not all trait methods implemented, missing: {}",
missing_methods.connect(", "));
}
}
@ -865,23 +864,17 @@ fn compare_impl_method(tcx: &ty::ctxt,
match (&trait_m.explicit_self, &impl_m.explicit_self) {
(&ast::SelfStatic, &ast::SelfStatic) => {}
(&ast::SelfStatic, _) => {
tcx.sess.span_err(
impl_m_span,
format!("method `{}` has a `{}` declaration in the impl, \
but not in the trait",
token::get_ident(trait_m.ident),
pprust::explicit_self_to_string(
impl_m.explicit_self)).as_slice());
span_err!(tcx.sess, impl_m_span, E0047,
"method `{}` has a `{}` declaration in the impl, but not in the trait",
token::get_ident(trait_m.ident),
pprust::explicit_self_to_string(impl_m.explicit_self));
return;
}
(_, &ast::SelfStatic) => {
tcx.sess.span_err(
impl_m_span,
format!("method `{}` has a `{}` declaration in the trait, \
but not in the impl",
token::get_ident(trait_m.ident),
pprust::explicit_self_to_string(
trait_m.explicit_self)).as_slice());
span_err!(tcx.sess, impl_m_span, E0048,
"method `{}` has a `{}` declaration in the trait, but not in the impl",
token::get_ident(trait_m.ident),
pprust::explicit_self_to_string(trait_m.explicit_self));
return;
}
_ => {
@ -892,28 +885,26 @@ fn compare_impl_method(tcx: &ty::ctxt,
let num_impl_m_type_params = impl_m.generics.types.len(subst::FnSpace);
let num_trait_m_type_params = trait_m.generics.types.len(subst::FnSpace);
if num_impl_m_type_params != num_trait_m_type_params {
tcx.sess.span_err(
impl_m_span,
format!("method `{}` has {} type parameter{} \
but its trait declaration has {} type parameter{}",
token::get_ident(trait_m.ident),
num_impl_m_type_params,
if num_impl_m_type_params == 1 {""} else {"s"},
num_trait_m_type_params,
if num_trait_m_type_params == 1 {""} else {"s"}).as_slice());
span_err!(tcx.sess, impl_m_span, E0049,
"method `{}` has {} type parameter{} \
but its trait declaration has {} type parameter{}",
token::get_ident(trait_m.ident),
num_impl_m_type_params,
if num_impl_m_type_params == 1 {""} else {"s"},
num_trait_m_type_params,
if num_trait_m_type_params == 1 {""} else {"s"});
return;
}
if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() {
tcx.sess.span_err(
impl_m_span,
format!("method `{}` has {} parameter{} \
but the declaration in trait `{}` has {}",
token::get_ident(trait_m.ident),
impl_m.fty.sig.inputs.len(),
if impl_m.fty.sig.inputs.len() == 1 {""} else {"s"},
ty::item_path_str(tcx, trait_m.def_id),
trait_m.fty.sig.inputs.len()).as_slice());
span_err!(tcx.sess, impl_m_span, E0050,
"method `{}` has {} parameter{} \
but the declaration in trait `{}` has {}",
token::get_ident(trait_m.ident),
impl_m.fty.sig.inputs.len(),
if impl_m.fty.sig.inputs.len() == 1 {""} else {"s"},
ty::item_path_str(tcx, trait_m.def_id),
trait_m.fty.sig.inputs.len());
return;
}
@ -1002,16 +993,13 @@ fn compare_impl_method(tcx: &ty::ctxt,
impl_param_def.bounds.builtin_bounds -
trait_param_def.bounds.builtin_bounds;
if !extra_bounds.is_empty() {
tcx.sess.span_err(
impl_m_span,
format!("in method `{}`, \
type parameter {} requires `{}`, \
which is not required by \
the corresponding type parameter \
in the trait declaration",
token::get_ident(trait_m.ident),
i,
extra_bounds.user_string(tcx)).as_slice());
span_err!(tcx.sess, impl_m_span, E0051,
"in method `{}`, type parameter {} requires `{}`, \
which is not required by the corresponding type parameter \
in the trait declaration",
token::get_ident(trait_m.ident),
i,
extra_bounds.user_string(tcx));
return;
}
@ -1043,17 +1031,12 @@ fn compare_impl_method(tcx: &ty::ctxt,
}
if !ok {
tcx.sess.span_err(impl_m_span,
format!("in method `{}`, type parameter {} \
requires bound `{}`, which is not \
required by the corresponding \
type parameter in the trait \
declaration",
token::get_ident(trait_m.ident),
i,
ppaux::trait_ref_to_string(
tcx,
&*impl_trait_bound)).as_slice())
span_err!(tcx.sess, impl_m_span, E0052,
"in method `{}`, type parameter {} requires bound `{}`, which is not \
required by the corresponding type parameter in the trait declaration",
token::get_ident(trait_m.ident),
i,
ppaux::trait_ref_to_string(tcx, &*impl_trait_bound));
}
}
}
@ -1071,11 +1054,10 @@ fn compare_impl_method(tcx: &ty::ctxt,
impl_fty, trait_fty) {
Ok(()) => {}
Err(ref terr) => {
tcx.sess.span_err(
impl_m_span,
format!("method `{}` has an incompatible type for trait: {}",
token::get_ident(trait_m.ident),
ty::type_err_to_str(tcx, terr)).as_slice());
span_err!(tcx.sess, impl_m_span, E0053,
"method `{}` has an incompatible type for trait: {}",
token::get_ident(trait_m.ident),
ty::type_err_to_str(tcx, terr));
ty::note_and_explain_type_err(tcx, terr);
}
}
@ -1162,10 +1144,8 @@ fn check_cast(fcx: &FnCtxt,
}, t_e, None);
}
} else if ty::get(t_1).sty == ty::ty_bool {
fcx.tcx()
.sess
.span_err(span,
"cannot cast as `bool`, compare with zero instead");
span_err!(fcx.tcx().sess, span, E0054,
"cannot cast as `bool`, compare with zero instead");
} else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) {
fn types_compatible(fcx: &FnCtxt, sp: Span,
t1: ty::t, t2: ty::t) -> bool {
@ -1533,9 +1513,9 @@ pub fn autoderef<T>(fcx: &FnCtxt, sp: Span, base_ty: ty::t,
}
// We've reached the recursion limit, error gracefully.
fcx.tcx().sess.span_err(sp,
format!("reached the recursion limit while auto-dereferencing {}",
base_ty.repr(fcx.tcx())).as_slice());
span_err!(fcx.tcx().sess, sp, E0055,
"reached the recursion limit while auto-dereferencing {}",
base_ty.repr(fcx.tcx()));
(ty::mk_err(), 0, None)
}
@ -1581,11 +1561,11 @@ fn try_overloaded_call(fcx: &FnCtxt,
write_call(fcx, call_expression, output_type);
if !fcx.tcx().sess.features.overloaded_calls.get() {
fcx.tcx().sess.span_err(call_expression.span,
"overloaded calls are experimental");
fcx.tcx().sess.span_note(call_expression.span,
"add `#[feature(overloaded_calls)]` to \
the crate attributes to enable");
span_err!(fcx.tcx().sess, call_expression.span, E0056,
"overloaded calls are experimental");
span_note!(fcx.tcx().sess, call_expression.span,
"add `#[feature(overloaded_calls)]` to \
the crate attributes to enable");
}
return true
@ -1783,14 +1763,12 @@ fn check_argument_types(fcx: &FnCtxt,
match ty::get(tuple_type).sty {
ty::ty_tup(ref arg_types) => {
if arg_types.len() != args.len() {
let msg = format!(
"this function takes {} parameter{} \
but {} parameter{} supplied",
arg_types.len(),
if arg_types.len() == 1 {""} else {"s"},
args.len(),
if args.len() == 1 {" was"} else {"s were"});
tcx.sess.span_err(sp, msg.as_slice());
span_err!(tcx.sess, sp, E0057,
"this function takes {} parameter{} but {} parameter{} supplied",
arg_types.len(),
if arg_types.len() == 1 {""} else {"s"},
args.len(),
if args.len() == 1 {" was"} else {"s were"});
err_args(args.len())
} else {
(*arg_types).clone()
@ -1798,21 +1776,17 @@ fn check_argument_types(fcx: &FnCtxt,
}
ty::ty_nil => {
if args.len() != 0 {
let msg = format!(
"this function takes 0 parameters \
but {} parameter{} supplied",
args.len(),
if args.len() == 1 {" was"} else {"s were"});
tcx.sess.span_err(sp, msg.as_slice());
span_err!(tcx.sess, sp, E0058,
"this function takes 0 parameters but {} parameter{} supplied",
args.len(),
if args.len() == 1 {" was"} else {"s were"});
}
Vec::new()
}
_ => {
tcx.sess
.span_err(sp,
"cannot use call notation; the first type \
parameter for the function trait is neither a \
tuple nor unit");
span_err!(tcx.sess, sp, E0059,
"cannot use call notation; the first type parameter \
for the function trait is neither a tuple nor unit");
err_args(supplied_arg_count)
}
}
@ -1822,29 +1796,22 @@ fn check_argument_types(fcx: &FnCtxt,
if supplied_arg_count >= expected_arg_count {
fn_inputs.iter().map(|a| *a).collect()
} else {
let msg = format!(
span_err!(tcx.sess, sp, E0060,
"this function takes at least {} parameter{} \
but {} parameter{} supplied",
expected_arg_count,
if expected_arg_count == 1 {""} else {"s"},
supplied_arg_count,
if supplied_arg_count == 1 {" was"} else {"s were"});
tcx.sess.span_err(sp, msg.as_slice());
expected_arg_count,
if expected_arg_count == 1 {""} else {"s"},
supplied_arg_count,
if supplied_arg_count == 1 {" was"} else {"s were"});
err_args(supplied_arg_count)
}
} else {
let msg = format!(
"this function takes {} parameter{} \
but {} parameter{} supplied",
expected_arg_count,
if expected_arg_count == 1 {""} else {"s"},
supplied_arg_count,
if supplied_arg_count == 1 {" was"} else {"s were"});
tcx.sess.span_err(sp, msg.as_slice());
span_err!(tcx.sess, sp, E0061,
"this function takes {} parameter{} but {} parameter{} supplied",
expected_arg_count,
if expected_arg_count == 1 {""} else {"s"},
supplied_arg_count,
if supplied_arg_count == 1 {" was"} else {"s were"});
err_args(supplied_arg_count)
};
@ -2730,11 +2697,9 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
error_happened = true;
}
Some((_, true)) => {
tcx.sess.span_err(
field.ident.span,
format!("field `{}` specified more than once",
token::get_ident(field.ident
.node)).as_slice());
span_err!(fcx.tcx().sess, field.ident.span, E0062,
"field `{}` specified more than once",
token::get_ident(field.ident.node));
error_happened = true;
}
Some((field_id, false)) => {
@ -2772,11 +2737,10 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
}
}
tcx.sess.span_err(span,
format!(
"missing field{}: {fields}",
if missing_fields.len() == 1 {""} else {"s"},
fields = missing_fields.connect(", ")).as_slice());
span_err!(tcx.sess, span, E0063,
"missing field{}: {}",
if missing_fields.len() == 1 {""} else {"s"},
missing_fields.connect(", "));
}
}
@ -2938,12 +2902,14 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
}
}
ast::ExprLit(_) => {
let error = if vst == ast::ExprVstoreSlice {
"`&\"string\"` has been removed; use `\"string\"` instead"
if vst == ast::ExprVstoreSlice {
span_err!(tcx.sess, expr.span, E0064,
"`&\"string\"` has been removed; use `\"string\"` instead");
} else {
"`box \"string\"` has been removed; use `\"string\".to_string()` instead"
};
tcx.sess.span_err(expr.span, error);
span_err!(tcx.sess, expr.span, E0065,
"`box \"string\"` has been removed; use \
`\"string\".to_string()` instead");
}
ty::mk_err()
}
_ => tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence"),
@ -2977,9 +2943,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
}
if !checked {
tcx.sess.span_err(expr.span,
"only the managed heap and exchange heap are \
currently supported");
span_err!(tcx.sess, expr.span, E0066,
"only the managed heap and exchange heap are currently supported");
fcx.write_ty(id, ty::mk_err());
}
}
@ -3011,7 +2976,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
let tcx = fcx.tcx();
if !ty::expr_is_lval(tcx, &**lhs) {
tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
span_err!(tcx.sess, lhs.span, E0067, "illegal left-hand side expression");
}
// Overwrite result of check_binop...this preserves existing behavior
@ -3077,7 +3042,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
};
if is_newtype {
// This is an obsolete struct deref
tcx.sess.span_err(expr.span,
span_err!(tcx.sess, expr.span, E0068,
"single-field tuple-structs can \
no longer be dereferenced");
} else {
@ -3181,8 +3146,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
ret_ty, ty::mk_nil()) {
Ok(_) => { /* fall through */ }
Err(_) => {
tcx.sess.span_err(
expr.span,
span_err!(tcx.sess, expr.span, E0069,
"`return;` in function returning non-nil");
}
},
@ -3201,7 +3165,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
let tcx = fcx.tcx();
if !ty::expr_is_lval(tcx, &**lhs) {
tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
span_err!(tcx.sess, expr.span, E0070,
"illegal left-hand side expression");
}
let lhs_ty = fcx.expr_ty(&**lhs);
@ -3390,11 +3355,9 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
base_expr);
}
_ => {
tcx.sess
.span_err(path.span,
format!("`{}` does not name a structure",
pprust::path_to_string(
path)).as_slice())
span_err!(tcx.sess, path.span, E0071,
"`{}` does not name a structure",
pprust::path_to_string(path));
}
}
}
@ -3766,10 +3729,10 @@ pub fn check_representable(tcx: &ty::ctxt,
// caught by case 1.
match ty::is_type_representable(tcx, sp, rty) {
ty::SelfRecursive => {
tcx.sess.span_err(
sp, format!("illegal recursive {} type; \
wrap the inner value in a box to make it representable",
designation).as_slice());
span_err!(tcx.sess, sp, E0072,
"illegal recursive {} type; \
wrap the inner value in a box to make it representable",
designation);
return false
}
ty::Representable | ty::ContainsRecursive => (),
@ -3794,12 +3757,10 @@ pub fn check_instantiable(tcx: &ty::ctxt,
-> bool {
let item_ty = ty::node_id_to_type(tcx, item_id);
if !ty::is_instantiable(tcx, item_ty) {
tcx.sess
.span_err(sp,
format!("this type cannot be instantiated without an \
instance of itself; consider using \
`Option<{}>`",
ppaux::ty_to_string(tcx, item_ty)).as_slice());
span_err!(tcx.sess, sp, E0073,
"this type cannot be instantiated without an \
instance of itself; consider using `Option<{}>`",
ppaux::ty_to_string(tcx, item_ty));
false
} else {
true
@ -3809,25 +3770,25 @@ pub fn check_instantiable(tcx: &ty::ctxt,
pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) {
let t = ty::node_id_to_type(tcx, id);
if ty::type_needs_subst(t) {
tcx.sess.span_err(sp, "SIMD vector cannot be generic");
span_err!(tcx.sess, sp, E0074, "SIMD vector cannot be generic");
return;
}
match ty::get(t).sty {
ty::ty_struct(did, ref substs) => {
let fields = ty::lookup_struct_fields(tcx, did);
if fields.is_empty() {
tcx.sess.span_err(sp, "SIMD vector cannot be empty");
span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty");
return;
}
let e = ty::lookup_field_type(tcx, did, fields.get(0).id, substs);
if !fields.iter().all(
|f| ty::lookup_field_type(tcx, did, f.id, substs) == e) {
tcx.sess.span_err(sp, "SIMD vector should be homogeneous");
span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous");
return;
}
if !ty::type_is_machine(e) {
tcx.sess.span_err(sp, "SIMD vector element type should be \
machine type");
span_err!(tcx.sess, sp, E0077,
"SIMD vector element type should be machine type");
return;
}
}
@ -3852,16 +3813,10 @@ pub fn check_enum_variants_sized(ccx: &CrateCtxt,
// A struct value with an unsized final field is itself
// unsized and we must track this in the type system.
if !ty::type_is_sized(ccx.tcx, *t) {
ccx.tcx
.sess
.span_err(
args.get(i).ty.span,
format!("type `{}` is dynamically sized. \
dynamically sized types may only \
appear as the final type in a \
variant",
ppaux::ty_to_string(ccx.tcx,
*t)).as_slice());
span_err!(ccx.tcx.sess, args.get(i).ty.span, E0078,
"type `{}` is dynamically sized. dynamically sized types may only \
appear as the final type in a variant",
ppaux::ty_to_string(ccx.tcx, *t));
}
}
},
@ -3947,14 +3902,12 @@ pub fn check_enum_variants(ccx: &CrateCtxt,
Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
Ok(_) => {
ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
span_err!(ccx.tcx.sess, e.span, E0079,
"expected signed integer constant");
}
Err(ref err) => {
ccx.tcx
.sess
.span_err(e.span,
format!("expected constant: {}",
*err).as_slice());
span_err!(ccx.tcx.sess, e.span, E0080,
"expected constant: {}", *err);
}
}
},
@ -3963,16 +3916,18 @@ pub fn check_enum_variants(ccx: &CrateCtxt,
// Check for duplicate discriminant values
if disr_vals.contains(&current_disr_val) {
ccx.tcx.sess.span_err(v.span, "discriminant value already exists");
span_err!(ccx.tcx.sess, v.span, E0081,
"discriminant value already exists");
}
// Check for unrepresentable discriminant values
match hint {
attr::ReprAny | attr::ReprExtern => (),
attr::ReprInt(sp, ity) => {
if !disr_in_range(ccx, ity, current_disr_val) {
ccx.tcx.sess.span_err(v.span,
"discriminant value outside specified type");
ccx.tcx.sess.span_note(sp, "discriminant type specified here");
span_err!(ccx.tcx.sess, v.span, E0082,
"discriminant value outside specified type");
span_note!(ccx.tcx.sess, sp,
"discriminant type specified here");
}
}
}
@ -3990,12 +3945,13 @@ pub fn check_enum_variants(ccx: &CrateCtxt,
let hint = ty::lookup_repr_hint(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id });
if hint != attr::ReprAny && vs.len() <= 1 {
let msg = if vs.len() == 1 {
"unsupported representation for univariant enum"
if vs.len() == 1 {
span_err!(ccx.tcx.sess, sp, E0083,
"unsupported representation for univariant enum");
} else {
"unsupported representation for zero-variant enum"
span_err!(ccx.tcx.sess, sp, E0084,
"unsupported representation for zero-variant enum");
};
ccx.tcx.sess.span_err(sp, msg)
}
let variants = do_check(ccx, vs, id, hint);
@ -4241,15 +4197,13 @@ pub fn instantiate_path(fcx: &FnCtxt,
segment: &ast::PathSegment)
{
for typ in segment.types.iter() {
fcx.tcx().sess.span_err(
typ.span,
span_err!(fcx.tcx().sess, typ.span, E0085,
"type parameters may not appear here");
break;
}
for lifetime in segment.lifetimes.iter() {
fcx.tcx().sess.span_err(
lifetime.span,
span_err!(fcx.tcx().sess, lifetime.span, E0086,
"lifetime parameters may not appear here");
break;
}
@ -4288,14 +4242,11 @@ pub fn instantiate_path(fcx: &FnCtxt,
if i < type_count {
substs.types.push(space, t);
} else if i == type_count {
fcx.tcx().sess.span_err(
typ.span,
format!(
"too many type parameters provided: \
expected at most {} parameter(s) \
but found {} parameter(s)",
type_count,
segment.types.len()).as_slice());
span_err!(fcx.tcx().sess, typ.span, E0087,
"too many type parameters provided: \
expected at most {} parameter(s) \
but found {} parameter(s)",
type_count, segment.types.len());
substs.types.truncate(space, 0);
}
}
@ -4309,13 +4260,11 @@ pub fn instantiate_path(fcx: &FnCtxt,
if i < region_count {
substs.mut_regions().push(space, r);
} else if i == region_count {
fcx.tcx().sess.span_err(
lifetime.span,
format!(
"too many lifetime parameters provided: \
expected {} parameter(s) but found {} parameter(s)",
region_count,
segment.lifetimes.len()).as_slice());
span_err!(fcx.tcx().sess, lifetime.span, E0088,
"too many lifetime parameters provided: \
expected {} parameter(s) but found {} parameter(s)",
region_count,
segment.lifetimes.len());
substs.mut_regions().truncate(space, 0);
}
}
@ -4360,14 +4309,10 @@ pub fn instantiate_path(fcx: &FnCtxt,
if provided_len < required_len {
let qualifier =
if desired.len() != required_len { "at least " } else { "" };
fcx.tcx().sess.span_err(
span,
format!("too few type parameters provided: \
expected {}{} parameter(s) \
but found {} parameter(s)",
qualifier,
required_len,
provided_len).as_slice());
span_err!(fcx.tcx().sess, span, E0089,
"too few type parameters provided: expected {}{} parameter(s) \
but found {} parameter(s)",
qualifier, required_len, provided_len);
substs.types.replace(space,
Vec::from_elem(desired.len(), ty::mk_err()));
return;
@ -4418,14 +4363,10 @@ pub fn instantiate_path(fcx: &FnCtxt,
// Otherwise, too few were provided. Report an error and then
// use inference variables.
fcx.tcx().sess.span_err(
span,
format!(
"too few lifetime parameters provided: \
expected {} parameter(s) \
but found {} parameter(s)",
desired.len(),
provided_len).as_slice());
span_err!(fcx.tcx().sess, span, E0090,
"too few lifetime parameters provided: expected {} parameter(s) \
but found {} parameter(s)",
desired.len(), provided_len);
substs.mut_regions().replace(
space,
@ -4547,10 +4488,9 @@ pub fn check_bounds_are_used(ccx: &CrateCtxt,
for (i, b) in tps_used.iter().enumerate() {
if !*b {
ccx.tcx.sess.span_err(
span,
format!("type parameter `{}` is unused",
token::get_ident(tps.get(i).ident)).as_slice());
span_err!(ccx.tcx.sess, span, E0091,
"type parameter `{}` is unused",
token::get_ident(tps.get(i).ident));
}
}
}
@ -4586,10 +4526,8 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
(0, Vec::new(), ty::mk_nil())
}
op => {
tcx.sess.span_err(it.span,
format!("unrecognized atomic operation \
function: `{}`",
op).as_slice());
span_err!(tcx.sess, it.span, E0092,
"unrecognized atomic operation function: `{}`", op);
return;
}
}
@ -4813,9 +4751,8 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
ty::mk_tup(tcx, vec!(ty::mk_u64(), ty::mk_bool()))),
ref other => {
tcx.sess.span_err(it.span,
format!("unrecognized intrinsic function: `{}`",
*other).as_slice());
span_err!(tcx.sess, it.span, E0093,
"unrecognized intrinsic function: `{}`", *other);
return;
}
}
@ -4833,11 +4770,10 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id));
let i_n_tps = i_ty.generics.types.len(subst::FnSpace);
if i_n_tps != n_tps {
tcx.sess.span_err(it.span,
format!("intrinsic has wrong number of type \
parameters: found {}, expected {}",
i_n_tps,
n_tps).as_slice());
span_err!(tcx.sess, it.span, E0094,
"intrinsic has wrong number of type \
parameters: found {}, expected {}",
i_n_tps, n_tps);
} else {
require_same_types(tcx,
None,

View File

@ -98,6 +98,9 @@ impl SpanHandler {
pub fn span_warn(&self, sp: Span, msg: &str) {
self.handler.emit(Some((&self.cm, sp)), msg, Warning);
}
pub fn span_warn_with_code(&self, sp: Span, msg: &str, code: &str) {
self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Warning);
}
pub fn span_note(&self, sp: Span, msg: &str) {
self.handler.emit(Some((&self.cm, sp)), msg, Note);
}

View File

@ -49,3 +49,25 @@ macro_rules! span_err(
($session).span_err_with_code($span, format!($($arg),*).as_slice(), stringify!($code))
})
)
#[macro_export]
macro_rules! span_warn(
($session:expr, $span:expr, $code:ident, $($arg:expr),*) => ({
__diagnostic_used!($code);
($session).span_warn_with_code($span, format!($($arg),*).as_slice(), stringify!($code))
})
)
#[macro_export]
macro_rules! span_note(
($session:expr, $span:expr, $($arg:expr),*) => ({
($session).span_note($span, format!($($arg),*).as_slice())
})
)
#[macro_export]
macro_rules! register_diagnostics(
($($code:tt),*) => (
$(register_diagnostic!($code))*
)
)

View File

@ -54,7 +54,8 @@ pub fn expand_diagnostic_used(ecx: &mut ExtCtxt, span: Span,
with_registered_diagnostics(|diagnostics| {
if !diagnostics.contains_key(&code.name) {
ecx.span_err(span, format!(
"unknown diagnostic code {}", token::get_ident(code).get()
"unknown diagnostic code {}; add to librustc/diagnostics.rs",
token::get_ident(code).get()
).as_slice());
}
()