From 953d6dfd7e1b1d5c5b17314b6e3bdec15d8e7a01 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 16 Jan 2015 15:54:58 -0800 Subject: [PATCH 1/7] Make error code registration work again. #19624 --- mk/tests.mk | 1 + src/etc/errorck.py | 70 ++++++++++++++++++++++++++++ src/librustc/diagnostics.rs | 20 ++------ src/librustc/lib.rs | 6 +-- src/librustc_driver/lib.rs | 15 +++++- src/librustc_resolve/diagnostics.rs | 18 +++++++ src/librustc_resolve/lib.rs | 4 ++ src/librustc_typeck/diagnostics.rs | 61 ++---------------------- src/librustc_typeck/lib.rs | 4 ++ src/libsyntax/diagnostics/plugin.rs | 7 +++ src/test/run-make/issue-19371/foo.rs | 2 +- 11 files changed, 128 insertions(+), 80 deletions(-) create mode 100644 src/etc/errorck.py create mode 100644 src/librustc_resolve/diagnostics.rs diff --git a/mk/tests.mk b/mk/tests.mk index 10452d91275..7a7287a2fbf 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 00000000000..17659309d3b --- /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 1ea79bdf606..c3b87fdd8aa 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -31,7 +31,6 @@ register_diagnostics! { E0010, E0011, E0012, - E0013, E0014, E0015, E0016, @@ -49,24 +48,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 62869064551..377e5dd39ff 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -54,7 +54,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; @@ -132,8 +134,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 50ff4546c37..f8e889fc711 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -61,7 +61,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; @@ -98,7 +97,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[]) { @@ -659,8 +658,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 00000000000..eed808bcd77 --- /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 31999faa6df..19b93ab2599 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -97,6 +97,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/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index c9e15b93ad4..68cf9ce0707 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,21 @@ 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 } + +__build_diagnostic_array! { DIAGNOSTICS } + diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 47b5cd4b11e..1fb292b86bf 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -111,6 +111,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; diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index 1469c50061c..0e99829fa1c 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 fe7df641159..867008cd259 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 } From 0c5225c5bf31dcca141c36ce1b5850ff2df79b9c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 17 Jan 2015 13:36:59 -0800 Subject: [PATCH 2/7] Add error codes to rustc_typeck --- src/librustc_typeck/astconv.rs | 84 +++++++++------------ src/librustc_typeck/check/closure.rs | 5 +- src/librustc_typeck/check/compare_method.rs | 21 +++--- src/librustc_typeck/check/mod.rs | 44 +++++------ src/librustc_typeck/check/vtable.rs | 23 +++--- src/librustc_typeck/check/wf.rs | 21 +++--- src/librustc_typeck/check/writeback.rs | 2 +- src/librustc_typeck/coherence/impls.rs | 7 +- src/librustc_typeck/coherence/mod.rs | 17 ++--- src/librustc_typeck/coherence/orphan.rs | 6 +- src/librustc_typeck/coherence/unsafety.rs | 22 +++--- src/librustc_typeck/collect.rs | 14 ++-- src/librustc_typeck/diagnostics.rs | 62 ++++++++++++++- src/librustc_typeck/lib.rs | 6 +- src/librustc_typeck/variance.rs | 2 +- 15 files changed, 179 insertions(+), 157 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 42b12c15866..080959cae0c 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) => { @@ -1557,8 +1551,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 }; @@ -1593,10 +1586,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, @@ -1633,9 +1625,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 { @@ -1666,10 +1657,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); } @@ -1693,9 +1683,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 } } @@ -1779,8 +1768,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 bfe43086aab..33cce67c780 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 27d4b2055d4..e3e5d67869f 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 f610456f73c..58b655d7585 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -801,16 +801,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"); } @@ -818,7 +817,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\"]`") } @@ -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) { 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 } }; @@ -2123,11 +2122,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 } @@ -2162,11 +2160,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 } } @@ -3880,10 +3877,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() @@ -3891,7 +3886,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); } } @@ -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)) } 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 } } @@ -4022,7 +4017,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 } } @@ -4872,8 +4867,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 3940092eb72..41b63830279 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 e6390212c60..60284433ffe 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 82da22eab98..52e81585875 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 2719a09f4f5..e535b86a7bf 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 350cee99f6a..7d59c3f9d3f 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 77d71e740d6..60b1fa5f4cf 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 e30d0a29938..867dea95885 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 80c0a72db83..664e5eaa45b 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(); 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"); } } @@ -1690,11 +1691,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 68cf9ce0707..ce30cb91c91 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -100,7 +100,67 @@ register_diagnostics! { E0178, 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 1fb292b86bf..aa99549bcd6 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -206,11 +206,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 86447e76a89..3df3e1bddc5 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() From f68029ec94415298e56ab20f73bcf2a1224ace4d Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 18 Jan 2015 13:39:18 -0800 Subject: [PATCH 3/7] Make fatal errors work with codes, add to typeck --- src/librustc/session/mod.rs | 3 ++ src/librustc_typeck/astconv.rs | 44 ++++++++++++++--------------- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/diagnostics.rs | 13 ++++++++- src/librustc_typeck/lib.rs | 2 +- src/libsyntax/diagnostic.rs | 4 +++ src/libsyntax/diagnostics/macros.rs | 8 ++++++ 7 files changed, 50 insertions(+), 26 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 5424b1c8cae..0392fbfdeae 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -69,6 +69,9 @@ impl Session { pub fn span_fatal(&self, sp: Span, msg: &str) -> ! { 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) -> ! { self.diagnostic().handler().fatal(msg) } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 080959cae0c..cfcc65bd15a 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -339,22 +339,22 @@ fn create_substs_for_ast_path<'tcx>( } else { "expected" }; - this.tcx().sess.span_fatal(span, - &format!("wrong number of type arguments: {} {}, found {}", + span_fatal!(this.tcx().sess, span, E0243, + "wrong number of type arguments: {} {}, found {}", expected, required_ty_param_count, - supplied_ty_param_count)[]); + supplied_ty_param_count); } else if supplied_ty_param_count > formal_ty_param_count { let expected = if required_ty_param_count < formal_ty_param_count { "expected at most" } else { "expected" }; - this.tcx().sess.span_fatal(span, - &format!("wrong number of type arguments: {} {}, found {}", + span_fatal!(this.tcx().sess, span, E0244, + "wrong number of type arguments: {} {}, found {}", expected, formal_ty_param_count, - supplied_ty_param_count)[]); + supplied_ty_param_count); } let mut substs = Substs::new_type(types, regions); @@ -557,10 +557,9 @@ pub fn instantiate_trait_ref<'tcx>( trait_ref } _ => { - this.tcx().sess.span_fatal( - ast_trait_ref.path.span, - &format!("`{}` is not a trait", - ast_trait_ref.path.user_string(this.tcx()))[]); + span_fatal!(this.tcx().sess, ast_trait_ref.path.span, E0245, + "`{}` is not a trait", + ast_trait_ref.path.user_string(this.tcx())); } } } @@ -1036,7 +1035,7 @@ pub fn ast_ty_to_ty<'tcx>( match ast_ty_to_ty_cache.get(&ast_ty.id) { Some(&ty::atttce_resolved(ty)) => return ty, 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 \ or struct in the cycle, if this is \ desired"); @@ -1136,9 +1135,9 @@ pub fn ast_ty_to_ty<'tcx>( ty::mk_self_type(tcx) } def::DefMod(id) => { - tcx.sess.span_fatal(ast_ty.span, - &format!("found module name used as a type: {}", - tcx.map.node_to_string(id.node))[]); + span_fatal!(tcx.sess, ast_ty.span, E0247, + "found module name used as a type: {}", + tcx.map.node_to_string(id.node)); } def::DefPrimTy(_) => { panic!("DefPrimTy arm missed in previous ast_ty_to_prim_ty call"); @@ -1164,10 +1163,10 @@ pub fn ast_ty_to_ty<'tcx>( associated_path_def_to_ty(this, ast_ty, provenance, assoc_ident.name) } _ => { - tcx.sess.span_fatal(ast_ty.span, - &format!("found value name used \ + span_fatal!(tcx.sess, ast_ty.span, E0248, + "found value name used \ as a type: {:?}", - a_def)[]); + a_def); } } } @@ -1185,17 +1184,16 @@ pub fn ast_ty_to_ty<'tcx>( ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), Some(i as uint)), _ => { - tcx.sess.span_fatal( - ast_ty.span, "expected constant expr for array length"); + span_fatal!(tcx.sess, ast_ty.span, E0249, + "expected constant expr for array length"); } } } Err(ref r) => { - tcx.sess.span_fatal( - ast_ty.span, - &format!("expected constant expr for array \ + span_fatal!(tcx.sess, ast_ty.span, E0250, + "expected constant expr for array \ length: {}", - *r)[]); + *r); } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 58b655d7585..db4962b0d22 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5224,7 +5224,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { "get_tydesc" => { let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) { 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 { ty: tydesc_ty, diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index ce30cb91c91..3627fa41160 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -160,7 +160,18 @@ register_diagnostics! { 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 + 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 } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index aa99549bcd6..78007f3552e 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -162,7 +162,7 @@ fn lookup_def_tcx(tcx:&ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def { match tcx.def_map.borrow().get(&id) { 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") } } } diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 7213b0fa955..b26ec64c24b 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -92,6 +92,10 @@ impl SpanHandler { self.handler.emit(Some((&self.cm, sp)), msg, Fatal); 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) { self.handler.emit(Some((&self.cm, sp)), msg, Error); self.handler.bump_err_count(); diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index 34a193dffd3..5bd683c86ae 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -14,6 +14,14 @@ macro_rules! register_diagnostic { ($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_rules! span_err { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ From cf629e7cfa54e4bd641dbbafa2297159a7c52749 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 18 Jan 2015 13:46:57 -0800 Subject: [PATCH 4/7] Add error codes to resolve --- src/librustc_resolve/diagnostics.rs | 12 +++++++++++- src/librustc_resolve/lib.rs | 30 ++++++++++++++--------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index eed808bcd77..2a4c31d62ab 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -12,7 +12,17 @@ register_diagnostics! { E0157, - E0153 + 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 } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 19b93ab2599..6b45c2443d3 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1722,7 +1722,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { in this module", namespace_name, 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 { let target = Target::new(containing_module.clone(), name_bindings.clone(), @@ -1769,7 +1769,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ValueNS => "value", }, token::get_name(name).get()); - self.session.span_err(import_span, &msg[]); + span_err!(self.session, import_span, E0252, "{}", &msg[]); } Some(_) | None => {} } @@ -1784,7 +1784,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if !name_bindings.defined_in_namespace_with(namespace, IMPORTABLE) { let msg = format!("`{}` is not directly importable", token::get_name(name)); - self.session.span_err(import_span, &msg[]); + span_err!(self.session, import_span, E0253, "{}", &msg[]); } } @@ -1809,7 +1809,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { crate in this module \ (maybe you meant `use {0}::*`?)", token::get_name(name).get()); - self.session.span_err(import_span, &msg[]); + span_err!(self.session, import_span, E0254, "{}", &msg[]); } Some(_) | None => {} } @@ -1831,7 +1831,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let msg = format!("import `{}` conflicts with value \ in this module", 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 { self.session.span_note(span, "conflicting value here"); @@ -1849,7 +1849,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let msg = format!("import `{}` conflicts with type in \ this module", 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 { self.session.span_note(span, "note conflicting type here") @@ -1862,7 +1862,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let msg = format!("inherent implementations \ are only allowed on types \ defined in the current module"); - self.session.span_err(span, &msg[]); + span_err!(self.session, span, E0257, "{}", &msg[]); self.session.span_note(import_span, "import from other module here") } @@ -1871,7 +1871,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let msg = format!("import `{}` conflicts with existing \ submodule", 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 { self.session.span_note(span, "note conflicting module here") @@ -1897,11 +1897,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if module.external_module_children.borrow().contains_key(&name) { - self.session - .span_err(span, - &format!("an external crate named `{}` has already \ + span_err!(self.session, span, E0259, + "an external crate named `{}` has already \ been imported into this module", - token::get_name(name).get())[]); + token::get_name(name).get()); } } @@ -1915,12 +1914,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if module.external_module_children.borrow().contains_key(&name) { - self.session - .span_err(span, - &format!("the name `{}` conflicts with an external \ + span_err!(self.session, span, E0260, + "the name `{}` conflicts with an external \ crate that has been imported into this \ module", - token::get_name(name).get())[]); + token::get_name(name).get()); } } From 9f59f7e0525ad44a11fb0614ef1626274ddaa918 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 18 Jan 2015 16:58:25 -0800 Subject: [PATCH 5/7] Add error codes to rustc --- src/librustc/diagnostics.rs | 47 +++++++++- src/librustc/middle/check_loop.rs | 8 +- src/librustc/middle/check_match.rs | 27 +++--- src/librustc/middle/check_static_recursion.rs | 8 +- src/librustc/middle/infer/error_reporting.rs | 39 ++++----- src/librustc/middle/liveness.rs | 5 +- src/librustc/middle/recursion_limit.rs | 2 +- src/librustc/middle/resolve_lifetime.rs | 23 ++--- src/librustc/middle/traits/error_reporting.rs | 87 +++++++------------ src/librustc/middle/traits/mod.rs | 9 +- src/librustc/middle/ty.rs | 18 ++-- src/librustc/middle/weak_lang_items.rs | 6 +- 12 files changed, 137 insertions(+), 142 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index c3b87fdd8aa..1dbd6eb4e8d 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -53,7 +53,52 @@ register_diagnostics! { E0161, E0162, E0165, - E0170 + E0170, + E0261, // use of undeclared lifetime name + E0262, // illegal lifetime parameter name + E0263, // lifetime name declared twice in same scope + E0264, // unknown external lang item + E0265, // recursive constant + E0266, // expected item + 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 } diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs index 1f779acac25..623f3525d4a 100644 --- a/src/librustc/middle/check_loop.rs +++ b/src/librustc/middle/check_loop.rs @@ -73,12 +73,12 @@ impl<'a> CheckLoopVisitor<'a> { match self.cx { Loop => {} Closure => { - self.sess.span_err(span, - &format!("`{}` inside of a closure", name)[]); + span_err!(self.sess, span, E0267, + "`{}` inside of a closure", name); } Normal => { - self.sess.span_err(span, - &format!("`{}` outside of loop", name)[]); + span_err!(self.sess, span, E0268, + "`{}` outside of loop", name); } } } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index a1a90395b3b..f6db0cf755b 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -226,11 +226,10 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &ast::Expr) { ast::ExprForLoop(ref pat, _, _, _) => { let mut static_inliner = StaticInliner::new(cx.tcx); is_refutable(cx, &*static_inliner.fold_pat((*pat).clone()), |uncovered_pat| { - cx.tcx.sess.span_err( - pat.span, - &format!("refutable pattern in `for` loop binding: \ + span_err!(cx.tcx.sess, pat.span, E0297, + "refutable pattern in `for` loop binding: \ `{}` not covered", - pat_to_string(uncovered_pat))[]); + pat_to_string(uncovered_pat)); }); // Check legality of move bindings. @@ -869,7 +868,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], Some(true) => Some(vec![]), Some(false) => 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 } } @@ -882,7 +881,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], Some(true) => Some(vec![]), Some(false) => 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 } } @@ -921,7 +920,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], } ast::PatMac(_) => { - cx.tcx.sess.span_err(pat_span, "unexpanded macro"); + span_err!(cx.tcx.sess, pat_span, E0300, "unexpanded macro"); None } }; @@ -1082,11 +1081,8 @@ impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> { _: LoanCause) { match kind { MutBorrow => { - self.cx - .tcx - .sess - .span_err(span, - "cannot mutably borrow in a pattern guard") + span_err!(self.cx.tcx.sess, span, E0301, + "cannot mutably borrow in a pattern guard") } 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) { match mode { JustWrite | WriteAndRead => { - self.cx - .tcx - .sess - .span_err(span, "cannot assign in a pattern guard") + span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard") } Init => {} } @@ -1120,7 +1113,7 @@ struct AtBindingPatternVisitor<'a, 'b:'a, 'tcx:'b> { impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> { fn visit_pat(&mut self, pat: &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 \ after an `@`"); } diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs index 86a58dae45a..4280b7fe3f0 100644 --- a/src/librustc/middle/check_static_recursion.rs +++ b/src/librustc/middle/check_static_recursion.rs @@ -83,7 +83,7 @@ pub fn check_item_recursion<'a>(sess: &'a Session, impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> { fn visit_item(&mut self, it: &ast::Item) { 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; } self.idstack.push(it.id); @@ -103,9 +103,9 @@ impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> { self.visit_item(item), ast_map::NodeForeignItem(_) => {}, _ => { - self.sess.span_err(e.span, - &format!("expected item, found {}", - self.ast_map.node_to_string(def_id.node))[]); + span_err!(self.sess, e.span, E0266, + "expected item, found {}", + self.ast_map.node_to_string(def_id.node)); return; }, } diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 1b9d6ec6c33..18c36f870b5 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -371,12 +371,11 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { infer::EquatePredicate(_) => "equality predicate not satisfied", }; - self.tcx.sess.span_err( - trace.origin.span(), - &format!("{}: {} ({})", + span_err!(self.tcx.sess, trace.origin.span(), E0308, + "{}: {} ({})", message_root_str, expected_found_str, - ty::type_err_to_str(self.tcx, terr))[]); + ty::type_err_to_str(self.tcx, terr)); match trace.origin { infer::MatchExpressionArm(_, arm_span) => @@ -443,9 +442,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { match sub { ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { // Does the required lifetime have a nice name we can print? - self.tcx.sess.span_err( - origin.span(), - &format!("{} may not live long enough", labeled_user_string)[]); + span_err!(self.tcx.sess, origin.span(), E0309, + "{} may not live long enough", labeled_user_string); self.tcx.sess.span_help( origin.span(), &format!( @@ -456,9 +454,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { ty::ReStatic => { // Does the required lifetime have a nice name we can print? - self.tcx.sess.span_err( - origin.span(), - &format!("{} may not live long enough", labeled_user_string)[]); + span_err!(self.tcx.sess, origin.span(), E0310, + "{} may not live long enough", labeled_user_string); self.tcx.sess.span_help( origin.span(), &format!( @@ -468,11 +465,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { _ => { // If not, be less specific. - self.tcx.sess.span_err( - origin.span(), - &format!( + span_err!(self.tcx.sess, origin.span(), E0311, "{} may not live long enough", - labeled_user_string)[]); + labeled_user_string); self.tcx.sess.span_help( origin.span(), &format!( @@ -499,8 +494,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { self.report_and_explain_type_error(trace, &terr); } infer::Reborrow(span) => { - self.tcx.sess.span_err( - span, + span_err!(self.tcx.sess, span, E0312, "lifetime of reference outlines \ lifetime of borrowed content..."); note_and_explain_region( @@ -515,14 +509,13 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { ""); } infer::ReborrowUpvar(span, ref upvar_id) => { - self.tcx.sess.span_err( - span, - &format!("lifetime of borrowed pointer outlives \ + span_err!(self.tcx.sess, span, E0313, + "lifetime of borrowed pointer outlives \ lifetime of captured variable `{}`...", ty::local_var_name_str(self.tcx, upvar_id.var_id) .get() - .to_string())[]); + .to_string()); note_and_explain_region( self.tcx, "...the borrowed pointer is valid for ", @@ -539,8 +532,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { ""); } infer::InfStackClosure(span) => { - self.tcx.sess.span_err( - span, + span_err!(self.tcx.sess, span, E0314, "closure outlives stack frame"); note_and_explain_region( self.tcx, @@ -554,8 +546,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { ""); } infer::InvokeClosure(span) => { - self.tcx.sess.span_err( - span, + span_err!(self.tcx.sess, span, E0315, "cannot invoke closure outside of its lifetime"); note_and_explain_region( self.tcx, diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 27a0324a3c4..f71779e2333 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1557,8 +1557,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { }, _ => false }; - self.ir.tcx.sess.span_err( - sp, "not all control paths return a value"); + span_err!(self.ir.tcx.sess, sp, E0269, "not all control paths return a value"); if ends_with_stmt { let last_stmt = body.stmts.first().unwrap(); let original_span = original_sp(self.ir.tcx.sess.codemap(), @@ -1575,7 +1574,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } ty::FnDiverging 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"); } diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/recursion_limit.rs index 017641bd3b7..81cbdf13c51 100644 --- a/src/librustc/middle/recursion_limit.rs +++ b/src/librustc/middle/recursion_limit.rs @@ -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\"]"); } } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index eff0018becc..be2b3026755 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -396,10 +396,9 @@ impl<'a> LifetimeContext<'a> { } fn unresolved_lifetime_ref(&self, lifetime_ref: &ast::Lifetime) { - self.sess.span_err( - lifetime_ref.span, - &format!("use of undeclared lifetime name `{}`", - token::get_name(lifetime_ref.name))[]); + span_err!(self.sess, lifetime_ref.span, E0261, + "use of undeclared lifetime name `{}`", + token::get_name(lifetime_ref.name)); } fn check_lifetime_defs(&mut self, old_scope: Scope, lifetimes: &Vec) { @@ -409,11 +408,9 @@ impl<'a> LifetimeContext<'a> { let special_idents = [special_idents::static_lifetime]; for lifetime in lifetimes.iter() { if special_idents.iter().any(|&i| i.name == lifetime.lifetime.name) { - self.sess.span_err( - lifetime.lifetime.span, - &format!("illegal lifetime parameter name: `{}`", - token::get_name(lifetime.lifetime.name)) - []); + span_err!(self.sess, lifetime.lifetime.span, E0262, + "illegal lifetime parameter name: `{}`", + token::get_name(lifetime.lifetime.name)); } } @@ -422,12 +419,10 @@ impl<'a> LifetimeContext<'a> { let lifetime_j = &lifetimes[j]; if lifetime_i.lifetime.name == lifetime_j.lifetime.name { - self.sess.span_err( - lifetime_j.lifetime.span, - &format!("lifetime name `{}` declared twice in \ + span_err!(self.sess, lifetime_j.lifetime.span, E0263, + "lifetime name `{}` declared twice in \ the same scope", - token::get_name(lifetime_j.lifetime.name)) - []); + token::get_name(lifetime_j.lifetime.name)); } } diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index 6d0e60ec495..93805750606 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -55,12 +55,10 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate); if !predicate.references_error() { - infcx.tcx.sess.span_err( - obligation.cause.span, - format!( + span_err!(infcx.tcx.sess, obligation.cause.span, E0271, "type mismatch resolving `{}`: {}", 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); } } @@ -97,28 +95,25 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, Position::ArgumentNamed(s) => match generic_map.get(s) { Some(val) => Some(val.as_slice()), None => { - infcx.tcx.sess - .span_err(err_sp, - format!("the #[rustc_on_unimplemented] \ + span_err!(infcx.tcx.sess, err_sp, E0272, + "the #[rustc_on_unimplemented] \ attribute on \ trait definition for {} refers to \ non-existent type parameter {}", - trait_str, s) - .as_slice()); + trait_str, s); errored = true; None } }, _ => { - infcx.tcx.sess - .span_err(err_sp, - format!("the #[rustc_on_unimplemented] \ + span_err!(infcx.tcx.sess, err_sp, E0273, + "the #[rustc_on_unimplemented] \ attribute on \ trait definition for {} must have named \ format arguments, \ eg `#[rustc_on_unimplemented = \ \"foo {{T}}\"]`", - trait_str).as_slice()); + trait_str); errored = true; None } @@ -130,11 +125,11 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, report = Some(err); } } else { - infcx.tcx.sess.span_err(err_sp, - format!("the #[rustc_on_unimplemented] attribute on \ + span_err!(infcx.tcx.sess, err_sp, E0274, + "the #[rustc_on_unimplemented] attribute on \ trait definition for {} must have a value, \ eg `#[rustc_on_unimplemented = \"foo\"]`", - trait_str).as_slice()); + trait_str); } 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. let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate); - infcx.tcx.sess.span_err( - obligation.cause.span, - format!( + span_err!(infcx.tcx.sess, obligation.cause.span, E0275, "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); @@ -165,12 +158,10 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, SelectionError::Unimplemented => { match &obligation.cause.code { &ObligationCauseCode::CompareImplMethodObligation => { - infcx.tcx.sess.span_err( - obligation.cause.span, - format!( + span_err!(infcx.tcx.sess, obligation.cause.span, E0276, "the requirement `{}` appears on the impl \ 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 { @@ -180,12 +171,10 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, if !trait_predicate.references_error() { let trait_ref = trait_predicate.to_poly_trait_ref(); - infcx.tcx.sess.span_err( - obligation.cause.span, - format!( + span_err!(infcx.tcx.sess, obligation.cause.span, E0277, "the trait `{}` is not implemented for the type `{}`", 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]" // error message, report with that message if it does 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 err = infcx.equality_predicate(obligation.cause.span, &predicate).unwrap_err(); - infcx.tcx.sess.span_err( - obligation.cause.span, - format!( + span_err!(infcx.tcx.sess, obligation.cause.span, E0278, "the requirement `{}` is not satisfied (`{}`)", 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) => { let predicate = infcx.resolve_type_vars_if_possible(predicate); let err = infcx.region_outlives_predicate(obligation.cause.span, &predicate).unwrap_err(); - infcx.tcx.sess.span_err( - obligation.cause.span, - format!( + span_err!(infcx.tcx.sess, obligation.cause.span, E0279, "the requirement `{}` is not satisfied (`{}`)", 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(..) => { let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate); - infcx.tcx.sess.span_err( - obligation.cause.span, - format!( + span_err!(infcx.tcx.sess, obligation.cause.span, E0280, "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 actual_trait_ref = infcx.resolve_type_vars_if_possible(&*actual_trait_ref); if !ty::type_is_error(actual_trait_ref.self_ty()) { - infcx.tcx.sess.span_err( - obligation.cause.span, - format!( + span_err!(infcx.tcx.sess, obligation.cause.span, E0281, "type mismatch: the type `{}` implements the trait `{}`, \ but the trait `{}` is required ({})", expected_trait_ref.self_ty().user_string(infcx.tcx), expected_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); } } @@ -293,18 +274,14 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, infcx.tcx.lang_items.sized_trait() .map_or(false, |sized_id| sized_id == trait_ref.def_id()) { - infcx.tcx.sess.span_err( - obligation.cause.span, - format!( + span_err!(infcx.tcx.sess, obligation.cause.span, E0282, "unable to infer enough type information about `{}`; \ type annotations required", - self_ty.user_string(infcx.tcx)).as_slice()); + self_ty.user_string(infcx.tcx)); } else { - infcx.tcx.sess.span_err( - obligation.cause.span, - format!( + span_err!(infcx.tcx.sess, obligation.cause.span, E0283, "type annotations required: cannot resolve `{}`", - predicate.user_string(infcx.tcx)).as_slice()); + predicate.user_string(infcx.tcx));; 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() { - infcx.tcx.sess.span_err( - obligation.cause.span, - format!( + span_err!(infcx.tcx.sess, obligation.cause.span, E0284, "type annotations required: cannot resolve `{}`", - predicate.user_string(infcx.tcx)).as_slice()); + predicate.user_string(infcx.tcx));; note_obligation_cause(infcx, obligation); } } diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 425765edf87..89459f95b87 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -379,11 +379,10 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, false } Err(Overflow) => { - infcx.tcx.sess.span_err( - span, - format!("overflow evaluating whether `{}` is `{}`", - ty.user_string(infcx.tcx), - bound.user_string(infcx.tcx)).as_slice()); + span_err!(infcx.tcx.sess, span, E0285, + "overflow evaluating whether `{}` is `{}`", + ty.user_string(infcx.tcx), + bound.user_string(infcx.tcx)); suggest_new_overflow_limit(infcx.tcx, span); false } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index be6c6b9d34f..e5bbd01dde6 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -5369,15 +5369,13 @@ pub fn enum_variants<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) discriminant = val as Disr } Ok(_) => { - cx.sess - .span_err(e.span, + span_err!(cx.sess, e.span, E0304, "expected signed integer constant"); } Err(ref err) => { - cx.sess - .span_err(e.span, - &format!("expected constant: {}", - *err)[]); + span_err!(cx.sess, e.span, E0305, + "expected constant: {}", + *err); } }, None => {} @@ -5851,9 +5849,9 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint { const_eval::const_binary(_) => "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 {}", - found)[]); + found); } Err(_) => { 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" }; - tcx.sess.span_err(count_expr.span, &format!( + span_err!(tcx.sess, count_expr.span, E0307, "expected constant integer for repeat count, found {}", - found)[]); + found); } } 0 diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 892a8004fec..25cca98c5fb 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -99,9 +99,9 @@ impl<'a> Context<'a> { self.items.missing.push(lang_items::$item); } } else)* { - self.sess.span_err(span, - format!("unknown external lang item: `{}`", - name).as_slice()); + span_err!(self.sess, span, E0264, + "unknown external lang item: `{}`", + name); } } } From 9a4401fe828f2f29c359bc3c83f6f3b7eed27d83 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Sat, 17 Jan 2015 17:20:24 -0800 Subject: [PATCH 6/7] Add some extended errors. --- src/librustc/diagnostics.rs | 40 ++++++++++++++++++++++++----- src/libsyntax/diagnostics/macros.rs | 6 +++++ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 1dbd6eb4e8d..b48df36a679 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -10,21 +10,49 @@ #![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, diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index 5bd683c86ae..9321d3ca3df 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -59,3 +59,9 @@ macro_rules! register_diagnostics { ) } +#[macro_export] +macro_rules! register_long_diagnostics { + ($($code:tt: $description:tt),*) => ( + $(register_diagnostic! { $code, $description })* + ) +} From 876b26645913f7e600f5919db166ec5db0219aaf Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 20 Jan 2015 14:18:35 -0800 Subject: [PATCH 7/7] Make multiline errors work with codes --- src/librustc/session/mod.rs | 115 ++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 52 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 0392fbfdeae..4150335abc3 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -76,61 +76,16 @@ impl Session { self.diagnostic().handler().fatal(msg) } pub fn span_err(&self, sp: Span, msg: &str) { - // 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 self.diagnostic().span_err(sp, msg); + match split_msg_into_multilines(msg) { + Some(msg) => self.diagnostic().span_err(sp, &msg[]), + None => 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) { - 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) { self.diagnostic().handler().err(msg) @@ -288,6 +243,62 @@ impl Session { } } +fn split_msg_into_multilines(msg: &str) -> Option { + // 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, local_crate_source_file: Option, registry: diagnostics::registry::Registry)