diff --git a/mk/tests.mk b/mk/tests.mk index c8c4beb11531b..22d2c50c26b3a 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -302,6 +302,7 @@ tidy: | grep '^$(S)src/libbacktrace' -v \ | grep '^$(S)src/rust-installer' -v \ | xargs $(CFG_PYTHON) $(S)src/etc/check-binaries.py + $(Q) $(CFG_PYTHON) $(S)src/etc/errorck.py $(S)src/ endif diff --git a/src/etc/errorck.py b/src/etc/errorck.py new file mode 100644 index 0000000000000..17659309d3b0d --- /dev/null +++ b/src/etc/errorck.py @@ -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 or the MIT license +# , 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) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 1ea79bdf606da..c2f98cdb5fc1d 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -10,28 +10,55 @@ #![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 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. -"## } +"##, + + 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! { E0002, - E0003, - E0004, - E0005, - E0006, E0007, E0008, E0009, E0010, E0011, E0012, - E0013, E0014, E0015, E0016, @@ -49,24 +76,13 @@ register_diagnostics! { E0137, E0138, E0139, - E0140, E0152, - E0153, - E0157, E0158, E0161, E0162, E0165, - E0166, - E0167, - E0168, - E0169, - E0170, - E0171, - E0172, - E0173, - E0174, - E0177, - E0178, - E0179 + E0170 } + +__build_diagnostic_array! { DIAGNOSTICS } + diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index b79f19413ef92..02bd527c0b47c 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -52,7 +52,9 @@ extern crate test; 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 use rustc_back::abi; @@ -130,8 +132,6 @@ pub mod lib { pub use llvm; } -__build_diagnostic_array! { DIAGNOSTICS } - // A private module so that macro-expanded idents like // `::rustc::lint::Lint` will also work in `rustc` itself. // diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 40a3eb9fe5b1d..6a13a66872550 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -59,7 +59,6 @@ use rustc::lint::Lint; use rustc::lint; use rustc::metadata; use rustc::metadata::creader::CrateOrString::Str; -use rustc::DIAGNOSTICS; use rustc::util::common::time; use std::cmp::Ordering::Equal; @@ -96,7 +95,7 @@ fn run_compiler(args: &[String]) { None => return }; - let descriptions = diagnostics::registry::Registry::new(&DIAGNOSTICS); + let descriptions = diagnostics_registry(); match matches.opt_str("explain") { Some(ref code) => { match descriptions.find_description(&code[]) { @@ -657,8 +656,20 @@ pub fn monitor(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() { let args = std::os::args(); let result = run(args); std::os::set_exit_status(result); } + diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs new file mode 100644 index 0000000000000..eed808bcd7772 --- /dev/null +++ b/src/librustc_resolve/diagnostics.rs @@ -0,0 +1,18 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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 +} + +__build_diagnostic_array! { DIAGNOSTICS } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 7743a437858d2..37f44bc1f2e28 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -95,6 +95,10 @@ use std::mem::replace; use std::rc::{Rc, Weak}; 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 record_exports; mod build_reduced_graph; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f2927dfd84340..c7b7f80909a51 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -100,8 +100,7 @@ pub trait AstConv<'tcx> { -> Ty<'tcx> { if ty::binds_late_bound_regions(self.tcx(), &poly_trait_ref) { - self.tcx().sess.span_err( - span, + span_err!(self.tcx().sess, span, E0212, "cannot extract an associated type from a higher-ranked trait bound \ in this context"); self.tcx().types.err @@ -119,8 +118,7 @@ pub trait AstConv<'tcx> { _item_name: ast::Name) -> Ty<'tcx> { - self.tcx().sess.span_err( - span, + span_err!(self.tcx().sess, span, E0213, "associated types are not accepted in this context"); self.tcx().types.err @@ -268,8 +266,7 @@ pub fn ast_path_substs_for_ty<'tcx>( convert_angle_bracketed_parameters(this, rscope, data) } ast::ParenthesizedParameters(ref data) => { - tcx.sess.span_err( - path.span, + span_err!(tcx.sess, path.span, E0214, "parenthesized parameters may only be used with a trait"); (Vec::new(), convert_parenthesized_parameters(this, data), Vec::new()) } @@ -610,7 +607,7 @@ fn ast_path_to_trait_ref<'a,'tcx>( if !this.tcx().sess.features.borrow().unboxed_closures && 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 \ used with the `Fn` family of traits, use parentheses"); span_help!(this.tcx().sess, path.span, @@ -626,7 +623,7 @@ fn ast_path_to_trait_ref<'a,'tcx>( if !this.tcx().sess.features.borrow().unboxed_closures && 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 \ used with the `Fn` family of traits"); span_help!(this.tcx().sess, path.span, @@ -738,32 +735,29 @@ fn ast_type_binding_to_projection_predicate<'tcx>( } if candidates.len() > 1 { - tcx.sess.span_err( - binding.span, - format!("ambiguous associated type: `{}` defined in multiple supertraits `{}`", + span_err!(tcx.sess, binding.span, E0217, + "ambiguous associated type: `{}` defined in multiple supertraits `{}`", token::get_name(binding.item_name), - candidates.user_string(tcx)).as_slice()); + candidates.user_string(tcx)); return Err(ErrorReported); } let candidate = match candidates.pop() { Some(c) => c, None => { - tcx.sess.span_err( - binding.span, - format!("no associated type `{}` defined in `{}`", + span_err!(tcx.sess, binding.span, E0218, + "no associated type `{}` defined in `{}`", token::get_name(binding.item_name), - trait_ref.user_string(tcx)).as_slice()); + trait_ref.user_string(tcx)); return Err(ErrorReported); } }; if ty::binds_late_bound_regions(tcx, &candidate) { - tcx.sess.span_err( - binding.span, - format!("associated type `{}` defined in higher-ranked supertrait `{}`", + span_err!(tcx.sess, binding.span, E0219, + "associated type `{}` defined in higher-ranked supertrait `{}`", token::get_name(binding.item_name), - candidate.user_string(tcx)).as_slice()); + candidate.user_string(tcx)); return Err(ErrorReported); } @@ -964,18 +958,18 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, } if suitable_bounds.len() == 0 { - tcx.sess.span_err(ast_ty.span, - format!("associated type `{}` not found for type parameter `{}`", + span_err!(tcx.sess, ast_ty.span, E0220, + "associated type `{}` not found for type parameter `{}`", token::get_name(assoc_name), - token::get_name(ty_param_name)).as_slice()); + token::get_name(ty_param_name)); return this.tcx().types.err; } if suitable_bounds.len() > 1 { - tcx.sess.span_err(ast_ty.span, - format!("ambiguous associated type `{}` in bounds of `{}`", + span_err!(tcx.sess, ast_ty.span, E0221, + "ambiguous associated type `{}` in bounds of `{}`", 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() { span_note!(this.tcx().sess, ast_ty.span, @@ -1093,7 +1087,7 @@ pub fn ast_ty_to_ty<'tcx>( ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ), ast::TyBareFn(ref bf) => { 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"); } let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl); @@ -1152,8 +1146,8 @@ pub fn ast_ty_to_ty<'tcx>( def::DefAssociatedTy(trait_type_id) => { let path_str = tcx.map.path_to_string( tcx.map.get_parent(trait_type_id.node)); - tcx.sess.span_err(ast_ty.span, - &format!("ambiguous associated \ + span_err!(tcx.sess, ast_ty.span, E0223, + "ambiguous associated \ type; specify the type \ using the syntax `::{}`", @@ -1163,7 +1157,7 @@ pub fn ast_ty_to_ty<'tcx>( .last() .unwrap() .identifier) - .get())[]); + .get()); this.tcx().types.err } def::DefAssociatedPath(provenance, assoc_ident) => { @@ -1549,8 +1543,7 @@ fn conv_ty_poly_trait_ref<'tcx>( None, &mut projection_bounds)) } else { - this.tcx().sess.span_err( - span, + span_err!(this.tcx().sess, span, E0224, "at least one non-builtin trait is required for an object type"); None }; @@ -1585,10 +1578,9 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>( if !trait_bounds.is_empty() { let b = &trait_bounds[0]; - this.tcx().sess.span_err( - b.trait_ref.path.span, - &format!("only the builtin traits can be used \ - as closure or object bounds")[]); + span_err!(this.tcx().sess, b.trait_ref.path.span, E0225, + "only the builtin traits can be used \ + as closure or object bounds"); } let region_bound = compute_region_bound(this, @@ -1625,9 +1617,8 @@ fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>, builtin_bounds.repr(tcx)); if explicit_region_bounds.len() > 1 { - tcx.sess.span_err( - explicit_region_bounds[1].span, - format!("only a single explicit lifetime bound is permitted").as_slice()); + span_err!(tcx.sess, explicit_region_bounds[1].span, E0226, + "only a single explicit lifetime bound is permitted"); } if explicit_region_bounds.len() != 0 { @@ -1658,10 +1649,9 @@ fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>, // error. let r = derived_region_bounds[0]; if derived_region_bounds.slice_from(1).iter().any(|r1| r != *r1) { - tcx.sess.span_err( - span, - &format!("ambiguous lifetime bound, \ - explicit lifetime bound required")[]); + span_err!(tcx.sess, span, E0227, + "ambiguous lifetime bound, \ + explicit lifetime bound required"); } return Some(r); } @@ -1685,9 +1675,8 @@ fn compute_region_bound<'tcx>( match rscope.default_region_bound(span) { Some(r) => { r } None => { - this.tcx().sess.span_err( - span, - &format!("explicit lifetime bound required")[]); + span_err!(this.tcx().sess, span, E0228, + "explicit lifetime bound required"); ty::ReStatic } } @@ -1771,8 +1760,7 @@ fn prohibit_projections<'tcx>(tcx: &ty::ctxt<'tcx>, bindings: &[ConvertedBinding<'tcx>]) { for binding in bindings.iter().take(1) { - tcx.sess.span_err( - binding.span, + span_err!(tcx.sess, binding.span, E0229, "associated type bindings are not allowed here"); } } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index bfe43086aab10..33cce67c7807d 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -50,10 +50,9 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, check_unboxed_closure(fcx, expr, kind, decl, body, None); - fcx.ccx.tcx.sess.span_err( - expr.span, + span_err!(fcx.ccx.tcx.sess, expr.span, E0187, "can't infer the \"kind\" of the closure, explicitly annotate it. e.g. \ - `|&:| {}`"); + `|&:| {{}}`"); }, Some((sig, kind)) => { check_unboxed_closure(fcx, expr, kind, decl, body, Some(sig)); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 27d4b2055d4cd..e3e5d67869fa4 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -59,23 +59,21 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, (&ty::StaticExplicitSelfCategory, &ty::StaticExplicitSelfCategory) => {} (&ty::StaticExplicitSelfCategory, _) => { - tcx.sess.span_err( - impl_m_span, - format!("method `{}` has a `{}` declaration in the impl, \ + span_err!(tcx.sess, impl_m_span, E0185, + "method `{}` has a `{}` declaration in the impl, \ but not in the trait", token::get_name(trait_m.name), ppaux::explicit_self_category_to_str( - &impl_m.explicit_self)).as_slice()); + &impl_m.explicit_self)); return; } (_, &ty::StaticExplicitSelfCategory) => { - tcx.sess.span_err( - impl_m_span, - format!("method `{}` has a `{}` declaration in the trait, \ + span_err!(tcx.sess, impl_m_span, E0186, + "method `{}` has a `{}` declaration in the trait, \ but not in the impl", token::get_name(trait_m.name), ppaux::explicit_self_category_to_str( - &trait_m.explicit_self)).as_slice()); + &trait_m.explicit_self)); 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 // the moment, give a kind of vague error message. if trait_params.len() != impl_params.len() { - tcx.sess.span_err( - span, - &format!("lifetime parameters or bounds on method `{}` do \ + span_err!(tcx.sess, span, E0195, + "lifetime parameters or bounds on method `{}` do \ not match the trait declaration", - token::get_name(impl_m.name))[]); + token::get_name(impl_m.name)); return false; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7e38321049ed7..a03b659fb7b24 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -802,16 +802,15 @@ fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }) { Some(_) => (), None => { - ccx.tcx.sess.span_err(attr.span, - format!("there is no type parameter \ + span_err!(ccx.tcx.sess, attr.span, E0230, + "there is no type parameter \ {} on trait {}", - s, item.ident.as_str()) - .as_slice()); + s, item.ident.as_str()); } }, // `{:1}` and `{}` are not to be used Position::ArgumentIs(_) | Position::ArgumentNext => { - ccx.tcx.sess.span_err(attr.span, + span_err!(ccx.tcx.sess, attr.span, E0231, "only named substitution \ parameters are allowed"); } @@ -819,7 +818,7 @@ fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } } else { - ccx.tcx.sess.span_err(attr.span, + span_err!(ccx.tcx.sess, attr.span, E0232, "this attribute must have a value, \ eg `#[rustc_on_unimplemented = \"foo\"]`") } @@ -2100,8 +2099,8 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let trait_did = match fcx.tcx().lang_items.require(IteratorItem) { Ok(trait_did) => trait_did, Err(ref err_string) => { - fcx.tcx().sess.span_err(iterator_expr.span, - &err_string[]); + span_err!(fcx.tcx().sess, iterator_expr.span, E0233, + "{}", &err_string[]); return fcx.tcx().types.err } }; @@ -2124,11 +2123,10 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, if !ty::type_is_error(true_expr_type) { let ty_string = fcx.infcx().ty_to_string(true_expr_type); - fcx.tcx().sess.span_err(iterator_expr.span, - &format!("`for` loop expression has type `{}` which does \ + span_err!(fcx.tcx().sess, iterator_expr.span, E0234, + "`for` loop expression has type `{}` which does \ not implement the `Iterator` trait; \ - maybe try .iter()", - ty_string)[]); + maybe try .iter()", ty_string); } fcx.tcx().types.err } @@ -2163,11 +2161,10 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fcx.tcx().types.err } _ => { - fcx.tcx().sess.span_err(iterator_expr.span, - &format!("`next` method of the `Iterator` \ + span_err!(fcx.tcx().sess, iterator_expr.span, E0239, + "`next` method of the `Iterator` \ trait has an unexpected type `{}`", - fcx.infcx().ty_to_string(return_type)) - []); + fcx.infcx().ty_to_string(return_type)); fcx.tcx().types.err } } @@ -3881,10 +3878,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, Err(type_error) => { let type_error_description = ty::type_err_to_str(tcx, &type_error); - fcx.tcx() - .sess - .span_err(path.span, - &format!("structure constructor specifies a \ + span_err!(fcx.tcx().sess, path.span, E0235, + "structure constructor specifies a \ structure of type `{}`, but this \ structure has type `{}`: {}", fcx.infcx() @@ -3892,7 +3887,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fcx.infcx() .ty_to_string( actual_structure_type), - type_error_description)[]); + type_error_description); ty::note_and_explain_type_err(tcx, &type_error); } } @@ -4013,7 +4008,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, ty::mk_struct(tcx, did, tcx.mk_substs(substs)) } 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 } } @@ -4023,7 +4018,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let substs = Substs::new_type(vec![], vec![]); ty::mk_struct(tcx, did, tcx.mk_substs(substs)) } 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 } } @@ -4873,8 +4868,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } ast::ParenthesizedParameters(ref data) => { - fcx.tcx().sess.span_err( - span, + span_err!(fcx.tcx().sess, span, E0238, "parenthesized parameters may only be used with a trait"); push_explicit_parenthesized_parameters_from_segment_to_substs( fcx, space, span, type_defs, data, substs); diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 3940092eb7291..41b63830279a8 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -51,7 +51,7 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, { let object_trait = object_trait(&object_trait_ty); 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"); } else { // 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(..)) => { - fcx.ccx.tcx.sess.span_err( - source_expr.span, - &format!("can only cast an boxed pointer \ + span_err!(fcx.ccx.tcx.sess, source_expr.span, E0189, + "can only cast a boxed pointer \ 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(..)) => { - fcx.ccx.tcx.sess.span_err( - source_expr.span, - &format!("can only cast a &-pointer \ + span_err!(fcx.ccx.tcx.sess, source_expr.span, E0190, + "can only cast a &-pointer \ 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() { - tcx.sess.span_err( - span, - format!("the value of the associated type `{}` (from the trait `{}`) must be specified", + span_err!(tcx.sess, span, E0191, + "the value of the associated type `{}` (from the trait `{}`) must be specified", name.user_string(tcx), - ty::item_path_str(tcx, trait_def_id)).as_slice()); + ty::item_path_str(tcx, trait_def_id)); } } diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index e6390212c6002..60284433ffe45 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -81,10 +81,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) { Some(ty::BoundSend) | Some(ty::BoundSync) => {} Some(_) | None => { - ccx.tcx.sess.span_err( - item.span, - format!("negative impls are currently \ - allowed just for `Send` and `Sync`").as_slice()) + span_err!(ccx.tcx.sess, item.span, E0192, + "negative impls are currently \ + allowed just for `Send` and `Sync`") } } } @@ -302,12 +301,11 @@ fn reject_non_type_param_bounds<'tcx>(tcx: &ty::ctxt<'tcx>, fn report_bound_error<'t>(tcx: &ty::ctxt<'t>, span: Span, bounded_ty: ty::Ty<'t>) { - tcx.sess.span_err( - span, - format!("cannot bound type `{}`, where clause \ + span_err!(tcx.sess, span, E0193, + "cannot bound type `{}`, where clause \ bounds may only be attached to types involving \ type parameters", - bounded_ty.repr(tcx)).as_slice()) + bounded_ty.repr(tcx)) } 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() { if impl_params.contains(&method_param.name) { - tcx.sess.span_err( - span, - &*format!("type parameter `{}` shadows another type parameter of the same name", - token::get_name(method_param.name))); + span_err!(tcx.sess, span, E0194, + "type parameter `{}` shadows another type parameter of the same name", + token::get_name(method_param.name)); } } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 82da22eab9837..52e81585875ab 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -416,7 +416,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { ResolvingUnboxedClosure(_) => { 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 \ unboxed closure") } diff --git a/src/librustc_typeck/coherence/impls.rs b/src/librustc_typeck/coherence/impls.rs index 2719a09f4f570..e535b86a7bfd1 100644 --- a/src/librustc_typeck/coherence/impls.rs +++ b/src/librustc_typeck/coherence/impls.rs @@ -34,10 +34,9 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for ImplsChecker<'cx, 'tcx> { match trait_ref.self_ty().sty { ty::ty_struct(..) | ty::ty_enum(..) => {} _ => { - self.tcx.sess.span_err( - item.span, - &format!("builtin traits can only be \ - implemented on structs or enums")[]); + span_err!(self.tcx.sess, item.span, E0209, + "builtin traits can only be \ + implemented on structs or enums"); } } } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index a7ef4c1e9f2a5..383da63c0fde7 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -490,24 +490,21 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { match ty::can_type_implement_copy(¶m_env, span, self_type) { Ok(()) => {} Err(ty::FieldDoesNotImplementCopy(name)) => { - tcx.sess - .span_err(span, - &format!("the trait `Copy` may not be \ + span_err!(tcx.sess, span, E0204, + "the trait `Copy` may not be \ implemented for this type; field \ `{}` does not implement `Copy`", - token::get_name(name))[]) + token::get_name(name)) } Err(ty::VariantDoesNotImplementCopy(name)) => { - tcx.sess - .span_err(span, - &format!("the trait `Copy` may not be \ + span_err!(tcx.sess, span, E0205, + "the trait `Copy` may not be \ implemented for this type; variant \ `{}` does not implement `Copy`", - token::get_name(name))[]) + token::get_name(name)) } Err(ty::TypeIsStructural) => { - tcx.sess - .span_err(span, + span_err!(tcx.sess, span, E0206, "the trait `Copy` may not be implemented \ for this type; type is not a structure or \ enumeration") diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 77d71e740d681..60b1fa5f4cf5d 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -89,13 +89,11 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { } Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => { if !ty::has_attr(self.tcx, trait_def_id, "old_orphan_check") { - self.tcx.sess.span_err( - item.span, - format!( + span_err!(self.tcx.sess, item.span, E0210, "type parameter `{}` is not constrained by any local type; \ only traits defined in the current crate can be implemented \ for a type parameter", - param_ty.user_string(self.tcx)).as_slice()); + param_ty.user_string(self.tcx)); self.tcx.sess.span_note( item.span, format!("for a limited time, you can add \ diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index e30d0a29938aa..867dea9588568 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -37,8 +37,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> { match unsafety { ast::Unsafety::Normal => { /* OK */ } ast::Unsafety::Unsafe => { - self.tcx.sess.span_err( - item.span, + span_err!(self.tcx.sess, item.span, E0197, "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) { (ast::Unsafety::Unsafe, ast::Unsafety::Unsafe, ast::ImplPolarity::Negative) => { - self.tcx.sess.span_err( - item.span, - format!("negative implementations are not unsafe").as_slice()); + span_err!(self.tcx.sess, item.span, E0198, + "negative implementations are not unsafe"); } (ast::Unsafety::Normal, ast::Unsafety::Unsafe, _) => { - self.tcx.sess.span_err( - item.span, - format!("implementing the trait `{}` is not unsafe", - trait_ref.user_string(self.tcx)).as_slice()); + span_err!(self.tcx.sess, item.span, E0199, + "implementing the trait `{}` is not unsafe", + trait_ref.user_string(self.tcx)); } (ast::Unsafety::Unsafe, ast::Unsafety::Normal, ast::ImplPolarity::Positive) => { - self.tcx.sess.span_err( - item.span, - format!("the trait `{}` requires an `unsafe impl` declaration", - trait_ref.user_string(self.tcx)).as_slice()); + span_err!(self.tcx.sess, item.span, E0200, + "the trait `{}` requires an `unsafe impl` declaration", + trait_ref.user_string(self.tcx)); } (ast::Unsafety::Unsafe, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index c56952abc4419..7e8ed4c965829 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -452,7 +452,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>, let mut seen_methods = FnvHashSet::new(); for m in ms { 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); @@ -608,7 +608,7 @@ fn convert(ccx: &CollectCtxt, it: &ast::Item) { } ast::TypeImplItem(ref typedef) => { 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"); } @@ -1160,7 +1160,8 @@ fn add_unsized_bound<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, assert!(ptr.bound_lifetimes.is_empty()); unbound = Some(ptr.trait_ref.clone()); } 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"); } } @@ -1688,11 +1689,10 @@ fn enforce_impl_ty_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>, impl trait, self type, or predicates", param_ty.user_string(tcx)).as_slice()); } else { - tcx.sess.span_err( - ty_param.span, - format!("the type parameter `{}` is not constrained by the \ + span_err!(tcx.sess, ty_param.span, E0207, + "the type parameter `{}` is not constrained by the \ impl trait, self type, or predicates", - param_ty.user_string(tcx)).as_slice()); + param_ty.user_string(tcx)); tcx.sess.span_help( ty_param.span, format!("you can temporarily opt out of this rule by placing \ diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index c9e15b93ad4c5..ce30cb91c91c8 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -10,38 +10,7 @@ #![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! { - E0002, - E0003, - E0004, - E0005, - E0006, - E0007, - E0008, - E0009, - E0010, - E0011, - E0012, - E0013, - E0014, - E0015, - E0016, - E0017, - E0018, - E0019, - E0020, - E0022, E0023, E0024, E0025, @@ -61,12 +30,9 @@ register_diagnostics! { E0046, E0049, E0050, - E0051, - E0052, E0053, E0054, E0055, - E0056, E0057, E0059, E0060, @@ -101,16 +67,12 @@ register_diagnostics! { E0092, E0093, E0094, - E0100, E0101, E0102, E0103, E0104, E0106, E0107, - E0108, - E0109, - E0110, E0116, E0117, E0118, @@ -125,38 +87,81 @@ register_diagnostics! { E0130, E0131, E0132, - E0133, - E0134, - E0135, - E0136, - E0137, - E0138, - E0139, - E0140, E0141, - E0152, - E0153, - E0157, - E0158, E0159, - E0161, - E0162, E0163, E0164, - E0165, E0166, E0167, E0168, - E0169, - E0171, E0172, E0173, // manual implementations of unboxed closure traits are experimental E0174, // explicit use of unboxed closure methods are experimental - E0177, E0178, - E0180, - E0181, E0182, 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 } + +__build_diagnostic_array! { DIAGNOSTICS } + diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 88fe88bf26540..16c597642719c 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -110,6 +110,10 @@ use syntax::ast_util::local_def; 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 rscope; mod astconv; @@ -201,11 +205,11 @@ fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>, match result { Ok(_) => true, Err(ref terr) => { - tcx.sess.span_err(span, - &format!("{}: {}", + span_err!(tcx.sess, span, E0211, + "{}: {}", msg(), ty::type_err_to_str(tcx, - terr))[]); + terr)); ty::note_and_explain_type_err(tcx, terr); false } diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index b33921e07e8dd..1fc547adb8315 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -1055,7 +1055,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { // attribute and report an error with various results if found. if ty::has_attr(tcx, item_def_id, "rustc_variance") { 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() diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index 34a193dffd3db..4bdc55686d6d2 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -51,3 +51,9 @@ macro_rules! register_diagnostics { ) } +#[macro_export] +macro_rules! register_long_diagnostics { + ($($code:tt: $description:tt),*) => ( + $(register_diagnostic! { $code, $description })* + ) +} diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index 1469c50061cc7..0e99829fa1c66 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -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, ())) } diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index fe7df6411599c..867008cd25917 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -44,7 +44,7 @@ fn basic_sess(sysroot: Path) -> Session { opts.output_types = vec![OutputTypeExe]; 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); sess }