diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index db22000fd9f5d..66ebd3081c0c7 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -40,6 +40,7 @@ use std::mem; use syntax::ast_util::{self, IdVisitingOperation}; use syntax::attr::{self, AttrMetaMethods}; use syntax::codemap::Span; +use syntax::errors::{self, DiagnosticBuilder}; use syntax::parse::token::InternedString; use syntax::ast; use syntax::attr::ThinAttributesExt; @@ -47,7 +48,6 @@ use rustc_front::hir; use rustc_front::util; use rustc_front::intravisit as hir_visit; use syntax::visit as ast_visit; -use syntax::errors; /// Information about the registered lints. /// @@ -363,10 +363,24 @@ pub fn gather_attrs(attrs: &[ast::Attribute]) /// in trans that run after the main lint pass is finished. Most /// lints elsewhere in the compiler should call /// `Session::add_lint()` instead. -pub fn raw_emit_lint(sess: &Session, lint: &'static Lint, - lvlsrc: LevelSource, span: Option, msg: &str) { +pub fn raw_emit_lint(sess: &Session, + lint: &'static Lint, + lvlsrc: LevelSource, + span: Option, + msg: &str) { + raw_struct_lint(sess, lint, lvlsrc, span, msg).map(|mut e| e.emit()); +} + +pub fn raw_struct_lint<'a>(sess: &'a Session, + lint: &'static Lint, + lvlsrc: LevelSource, + span: Option, + msg: &str) + -> Option> { let (mut level, source) = lvlsrc; - if level == Allow { return } + if level == Allow { + return None; + } let name = lint.name_lower(); let mut def = None; @@ -391,17 +405,18 @@ pub fn raw_emit_lint(sess: &Session, lint: &'static Lint, // For purposes of printing, we can treat forbid as deny. if level == Forbid { level = Deny; } - match (level, span) { - (Warn, Some(sp)) => sess.span_warn(sp, &msg[..]), - (Warn, None) => sess.warn(&msg[..]), - (Deny, Some(sp)) => sess.span_err(sp, &msg[..]), - (Deny, None) => sess.err(&msg[..]), + let mut err = match (level, span) { + (Warn, Some(sp)) => sess.struct_span_warn(sp, &msg[..]), + (Warn, None) => sess.struct_warn(&msg[..]), + (Deny, Some(sp)) => sess.struct_span_err(sp, &msg[..]), + (Deny, None) => sess.struct_err(&msg[..]), _ => sess.bug("impossible level in raw_emit_lint"), - } + }; if let Some(span) = def { - sess.span_note(span, "lint level defined here"); + err.span_note(span, "lint level defined here"); } + Some(err) } pub trait LintContext: Sized { @@ -418,44 +433,80 @@ pub trait LintContext: Sized { self.lints().levels.get(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl) } - fn lookup_and_emit(&self, lint: &'static Lint, span: Option, msg: &str) { - let (level, src) = match self.lints().levels.get(&LintId::of(lint)) { - None => return, - Some(&(Warn, src)) => { + fn level_src(&self, lint: &'static Lint) -> Option { + self.lints().levels.get(&LintId::of(lint)).map(|ls| match ls { + &(Warn, src) => { let lint_id = LintId::of(builtin::WARNINGS); (self.lints().get_level_source(lint_id).0, src) } - Some(&pair) => pair, + _ => *ls + }) + } + + fn lookup_and_emit(&self, lint: &'static Lint, span: Option, msg: &str) { + let (level, src) = match self.level_src(lint) { + None => return, + Some(pair) => pair, }; raw_emit_lint(&self.sess(), lint, (level, src), span, msg); } + fn lookup(&self, + lint: &'static Lint, + span: Option, + msg: &str) + -> Option { + let (level, src) = match self.level_src(lint) { + None => return None, + Some(pair) => pair, + }; + + raw_struct_lint(&self.sess(), lint, (level, src), span, msg) + } + /// Emit a lint at the appropriate level, for a particular span. fn span_lint(&self, lint: &'static Lint, span: Span, msg: &str) { self.lookup_and_emit(lint, Some(span), msg); } + fn struct_span_lint(&self, + lint: &'static Lint, + span: Span, + msg: &str) + -> Option { + self.lookup(lint, Some(span), msg) + } + /// Emit a lint and note at the appropriate level, for a particular span. fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str, note_span: Span, note: &str) { - self.span_lint(lint, span, msg); + let mut err = match self.lookup(lint, Some(span), msg) { + Some(e) => e, + None => return + }; if self.current_level(lint) != Level::Allow { if note_span == span { - self.sess().fileline_note(note_span, note) + err.fileline_note(note_span, note); } else { - self.sess().span_note(note_span, note) + err.span_note(note_span, note); } } + err.emit(); } /// Emit a lint and help at the appropriate level, for a particular span. fn span_lint_help(&self, lint: &'static Lint, span: Span, msg: &str, help: &str) { + let mut err = match self.lookup(lint, Some(span), msg) { + Some(e) => e, + None => return + }; self.span_lint(lint, span, msg); if self.current_level(lint) != Level::Allow { - self.sess().span_help(span, help) + err.span_help(span, help); } + err.emit(); } /// Emit a lint at the appropriate level, with no associated span. diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 23be6117f190f..9c689daab86a7 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -41,7 +41,7 @@ use rustc_front::hir; pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore, raw_emit_lint, check_crate, check_ast_crate, gather_attrs, - GatherNodeLevels}; + raw_struct_lint, GatherNodeLevels}; /// Specification of a single lint. #[derive(Copy, Clone, Debug)] diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index d6f05ffd8a513..c2acd0e4795c9 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -224,14 +224,15 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { // this doesn't come from a macro that has #[allow_internal_unstable] !self.tcx.sess.codemap().span_allows_unstable(expr.span) { - self.tcx.sess.span_err( + let mut err = self.tcx.sess.struct_span_err( expr.span, "const fns are an unstable feature"); fileline_help!( - self.tcx.sess, + &mut err, expr.span, "in Nightly builds, add `#![feature(const_fn)]` to the crate \ attributes to enable"); + err.emit(); } let qualif = self.fn_like(fn_like.kind(), @@ -714,27 +715,27 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, if !is_const { v.add_qualif(ConstQualif::NOT_CONST); if v.mode != Mode::Var { - fn span_limited_call_error(tcx: &ty::ctxt, span: Span, s: &str) { - span_err!(tcx.sess, span, E0015, "{}", s); - } - // FIXME(#24111) Remove this check when const fn stabilizes - if let UnstableFeatures::Disallow = v.tcx.sess.opts.unstable_features { - span_limited_call_error(&v.tcx, e.span, - &format!("function calls in {}s are limited to \ - struct and enum constructors", - v.msg())); - v.tcx.sess.span_note(e.span, - "a limited form of compile-time function \ - evaluation is available on a nightly \ - compiler via `const fn`"); + let (msg, note) = + if let UnstableFeatures::Disallow = v.tcx.sess.opts.unstable_features { + (format!("function calls in {}s are limited to \ + struct and enum constructors", + v.msg()), + Some("a limited form of compile-time function \ + evaluation is available on a nightly \ + compiler via `const fn`")) } else { - span_limited_call_error(&v.tcx, e.span, - &format!("function calls in {}s are limited \ - to constant functions, \ - struct and enum constructors", - v.msg())); + (format!("function calls in {}s are limited \ + to constant functions, \ + struct and enum constructors", + v.msg()), + None) + }; + let mut err = struct_span_err!(v.tcx.sess, e.span, E0015, "{}", msg); + if let Some(note) = note { + err.span_note(e.span, note); } + err.emit(); } } } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index cab7e45ee6283..8439b439d7649 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -215,12 +215,13 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) { if inlined_arms.is_empty() { if !pat_ty.is_empty(cx.tcx) { // We know the type is inhabited, so this must be wrong - span_err!(cx.tcx.sess, ex.span, E0002, - "non-exhaustive patterns: type {} is non-empty", - pat_ty); - span_help!(cx.tcx.sess, ex.span, + let mut err = struct_span_err!(cx.tcx.sess, ex.span, E0002, + "non-exhaustive patterns: type {} is non-empty", + pat_ty); + span_help!(&mut err, ex.span, "Please ensure that all possible cases are being handled; \ possibly adding wildcards or more match arms."); + err.emit(); } // If the type *is* empty, it's vacuously exhaustive return; @@ -251,14 +252,15 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) && variant.kind() == VariantKind::Unit ) { let ty_path = cx.tcx.item_path_str(edef.did); - span_warn!(cx.tcx.sess, p.span, E0170, + let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170, "pattern binding `{}` is named the same as one \ of the variants of the type `{}`", ident.node, ty_path); - fileline_help!(cx.tcx.sess, p.span, + fileline_help!(err, p.span, "if you meant to match on a variant, \ consider making the path in the pattern qualified: `{}::{}`", ty_path, ident.node); + err.emit(); } } } @@ -282,13 +284,13 @@ fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) { Ok(_) => {} Err(err) => { - span_err!(cx.tcx.sess, err.span, E0471, - "constant evaluation error: {}", - err.description()); + let mut diag = struct_span_err!(cx.tcx.sess, err.span, E0471, + "constant evaluation error: {}", + err.description()); if !p.span.contains(err.span) { - cx.tcx.sess.span_note(p.span, - "in pattern here") + diag.span_note(p.span, "in pattern here"); } + diag.emit(); } } } @@ -1076,9 +1078,10 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, } else if has_guard { span_err!(cx.tcx.sess, p.span, E0008, "cannot bind by-move into a pattern guard"); } else if by_ref_span.is_some() { - span_err!(cx.tcx.sess, p.span, E0009, - "cannot bind by-move and by-ref in the same pattern"); - span_note!(cx.tcx.sess, by_ref_span.unwrap(), "by-ref binding occurs here"); + let mut err = struct_span_err!(cx.tcx.sess, p.span, E0009, + "cannot bind by-move and by-ref in the same pattern"); + span_note!(&mut err, by_ref_span.unwrap(), "by-ref binding occurs here"); + err.emit(); } }; diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index ab5153e1a61d4..aac6f1edc051d 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -243,10 +243,11 @@ fn add_library(sess: &session::Session, // This error is probably a little obscure, but I imagine that it // can be refined over time. if link2 != link || link == RequireStatic { - sess.err(&format!("cannot satisfy dependencies so `{}` only \ - shows up once", sess.cstore.crate_name(cnum))); - sess.help("having upstream crates all available in one format \ - will likely make this go away"); + sess.struct_err(&format!("cannot satisfy dependencies so `{}` only \ + shows up once", sess.cstore.crate_name(cnum))) + .help("having upstream crates all available in one format \ + will likely make this go away") + .emit(); } } None => { m.insert(cnum, link); } diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index ecf16aaed836a..2d096f66e09f6 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -146,17 +146,20 @@ fn configure_main(this: &mut EntryContext) { this.session.entry_type.set(Some(config::EntryMain)); } else { // No main function - this.session.err("main function not found"); + let mut err = this.session.struct_err("main function not found"); if !this.non_main_fns.is_empty() { // There were some functions named 'main' though. Try to give the user a hint. - this.session.note("the main function must be defined at the crate level \ - but you have one or more functions named 'main' that are not \ - defined at the crate level. Either move the definition or \ - attach the `#[main]` attribute to override this behavior."); + err.note("the main function must be defined at the crate level \ + but you have one or more functions named 'main' that are not \ + defined at the crate level. Either move the definition or \ + attach the `#[main]` attribute to override this behavior."); for &(_, span) in &this.non_main_fns { - this.session.span_note(span, "here is a function named 'main'"); + err.span_note(span, "here is a function named 'main'"); } + err.emit(); this.session.abort_if_errors(); + } else { + err.emit(); } } } diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 181e0c0fbc86b..5382e328a113b 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -90,12 +90,14 @@ use std::cell::{Cell, RefCell}; use std::char::from_u32; use std::fmt; use syntax::ast; +use syntax::errors::DiagnosticBuilder; use syntax::codemap::{self, Pos, Span}; use syntax::parse::token; use syntax::ptr::P; impl<'tcx> ty::ctxt<'tcx> { pub fn note_and_explain_region(&self, + err: &mut DiagnosticBuilder, prefix: &str, region: ty::Region, suffix: &str) { @@ -126,7 +128,10 @@ impl<'tcx> ty::ctxt<'tcx> { }; let span = match scope.span(&self.region_maps, &self.map) { Some(s) => s, - None => return self.sess.note(&unknown_scope()) + None => { + err.note(&unknown_scope()); + return; + } }; let tag = match self.map.find(scope.node_id(&self.region_maps)) { Some(ast_map::NodeBlock(_)) => "block", @@ -142,7 +147,8 @@ impl<'tcx> ty::ctxt<'tcx> { Some(ast_map::NodeStmt(_)) => "statement", Some(ast_map::NodeItem(it)) => item_scope_tag(&*it), Some(_) | None => { - return self.sess.span_note(span, &unknown_scope()); + err.span_note(span, &unknown_scope()); + return; } }; let scope_decorated_tag = match self.region_maps.code_extent_data(scope) { @@ -214,9 +220,9 @@ impl<'tcx> ty::ctxt<'tcx> { }; let message = format!("{}{}{}", prefix, description, suffix); if let Some(span) = span { - self.sess.span_note(span, &message); + err.span_note(span, &message); } else { - self.sess.note(&message); + err.note(&message); } } } @@ -228,9 +234,15 @@ pub trait ErrorReporting<'tcx> { fn process_errors(&self, errors: &Vec>) -> Vec>; - fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>); + fn report_type_error(&self, + trace: TypeTrace<'tcx>, + terr: &TypeError<'tcx>) + -> Option>; - fn check_and_note_conflicting_crates(&self, terr: &TypeError<'tcx>, sp: Span); + fn check_and_note_conflicting_crates(&self, + err: &mut DiagnosticBuilder, + terr: &TypeError<'tcx>, + sp: Span); fn report_and_explain_type_error(&self, trace: TypeTrace<'tcx>, @@ -265,17 +277,20 @@ pub trait ErrorReporting<'tcx> { trace_origin: &[(TypeTrace<'tcx>, TypeError<'tcx>)], same_regions: &[SameRegions]); - fn give_suggestion(&self, same_regions: &[SameRegions]); + fn give_suggestion(&self, err: &mut DiagnosticBuilder, same_regions: &[SameRegions]); } trait ErrorReportingHelpers<'tcx> { fn report_inference_failure(&self, - var_origin: RegionVariableOrigin); + var_origin: RegionVariableOrigin) + -> DiagnosticBuilder<'tcx>; fn note_region_origin(&self, + err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>); fn give_expl_lifetime_param(&self, + err: &mut DiagnosticBuilder, decl: &hir::FnDecl, unsafety: hir::Unsafety, constness: hir::Constness, @@ -460,35 +475,47 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { } } - fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>) { + fn report_type_error(&self, + trace: TypeTrace<'tcx>, + terr: &TypeError<'tcx>) + -> Option> { let expected_found_str = match self.values_str(&trace.values) { Some(v) => v, None => { - return; /* derived error */ + return None; /* derived error */ } }; - span_err!(self.tcx.sess, trace.origin.span(), E0308, - "{}: {} ({})", - trace.origin, - expected_found_str, - terr); + let mut err = struct_span_err!(self.tcx.sess, + trace.origin.span(), + E0308, + "{}: {} ({})", + trace.origin, + expected_found_str, + terr); - self.check_and_note_conflicting_crates(terr, trace.origin.span()); + self.check_and_note_conflicting_crates(&mut err, terr, trace.origin.span()); match trace.origin { TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source { - hir::MatchSource::IfLetDesugar{..} => - self.tcx.sess.span_note(arm_span, "`if let` arm with an incompatible type"), - _ => self.tcx.sess.span_note(arm_span, "match arm with an incompatible type"), + hir::MatchSource::IfLetDesugar{..} => { + err.span_note(arm_span, "`if let` arm with an incompatible type"); + } + _ => { + err.span_note(arm_span, "match arm with an incompatible type"); + } }, _ => () } + Some(err) } /// Adds a note if the types come from similarly named crates - fn check_and_note_conflicting_crates(&self, terr: &TypeError<'tcx>, sp: Span) { - let report_path_match = |did1: DefId, did2: DefId| { + fn check_and_note_conflicting_crates(&self, + err: &mut DiagnosticBuilder, + terr: &TypeError<'tcx>, + sp: Span) { + let report_path_match = |err: &mut DiagnosticBuilder, did1: DefId, did2: DefId| { // Only external crates, if either is from a local // module we could have false positives if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate { @@ -502,9 +529,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { // for imported and non-imported crates if exp_path == found_path { let crate_name = self.tcx.sess.cstore.crate_name(did1.krate); - self.tcx.sess.span_note(sp, &format!("Perhaps two different versions \ - of crate `{}` are being used?", - crate_name)); + err.span_note(sp, &format!("Perhaps two different versions \ + of crate `{}` are being used?", + crate_name)); } } }; @@ -517,13 +544,13 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { (&ty::TyStruct(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) | (&ty::TyEnum(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) | (&ty::TyStruct(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) => { - report_path_match(exp_adt.did, found_adt.did); + report_path_match(err, exp_adt.did, found_adt.did); }, _ => () } }, TypeError::Traits(ref exp_found) => { - report_path_match(exp_found.expected, exp_found.found); + report_path_match(err, exp_found.expected, exp_found.found); }, _ => () // FIXME(#22750) handle traits and stuff } @@ -533,8 +560,11 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>) { let span = trace.origin.span(); - self.report_type_error(trace, terr); - self.tcx.note_and_explain_type_err(terr, span); + let err = self.report_type_error(trace, terr); + err.map(|mut err| { + self.tcx.note_and_explain_type_err(&mut err, terr, span); + err.emit(); + }); } /// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived @@ -584,51 +614,56 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { format!("the associated type `{}`", p), }; - match sub { + let mut err = match sub { ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { // Does the required lifetime have a nice name we can print? - span_err!( - self.tcx.sess, origin.span(), E0309, - "{} may not live long enough", labeled_user_string); - self.tcx.sess.fileline_help( - origin.span(), - &format!( - "consider adding an explicit lifetime bound `{}: {}`...", - bound_kind, - sub)); + let mut err = struct_span_err!(self.tcx.sess, + origin.span(), + E0309, + "{} may not live long enough", + labeled_user_string); + err.fileline_help(origin.span(), + &format!("consider adding an explicit lifetime bound `{}: {}`...", + bound_kind, + sub)); + err } ty::ReStatic => { // Does the required lifetime have a nice name we can print? - span_err!( - self.tcx.sess, origin.span(), E0310, - "{} may not live long enough", labeled_user_string); - self.tcx.sess.fileline_help( - origin.span(), - &format!( - "consider adding an explicit lifetime bound `{}: 'static`...", - bound_kind)); + let mut err = struct_span_err!(self.tcx.sess, + origin.span(), + E0310, + "{} may not live long enough", + labeled_user_string); + err.fileline_help(origin.span(), + &format!("consider adding an explicit lifetime \ + bound `{}: 'static`...", + bound_kind)); + err } _ => { // If not, be less specific. - span_err!( - self.tcx.sess, origin.span(), E0311, - "{} may not live long enough", - labeled_user_string); - self.tcx.sess.fileline_help( - origin.span(), - &format!( - "consider adding an explicit lifetime bound for `{}`", - bound_kind)); + let mut err = struct_span_err!(self.tcx.sess, + origin.span(), + E0311, + "{} may not live long enough", + labeled_user_string); + err.fileline_help(origin.span(), + &format!("consider adding an explicit lifetime bound for `{}`", + bound_kind)); self.tcx.note_and_explain_region( + &mut err, &format!("{} must be valid for ", labeled_user_string), sub, "..."); + err } - } + }; - self.note_region_origin(&origin); + self.note_region_origin(&mut err, &origin); + err.emit(); } fn report_concrete_failure(&self, @@ -641,239 +676,262 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { self.report_and_explain_type_error(trace, &terr); } infer::Reborrow(span) => { - span_err!(self.tcx.sess, span, E0312, + let mut err = struct_span_err!(self.tcx.sess, span, E0312, "lifetime of reference outlines \ lifetime of borrowed content..."); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "...the reference is valid for ", sub, "..."); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "...but the borrowed content is only valid for ", sup, ""); + err.emit(); } infer::ReborrowUpvar(span, ref upvar_id) => { - span_err!(self.tcx.sess, span, E0313, + let mut err = struct_span_err!(self.tcx.sess, span, E0313, "lifetime of borrowed pointer outlives \ lifetime of captured variable `{}`...", self.tcx.local_var_name_str(upvar_id.var_id)); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "...the borrowed pointer is valid for ", sub, "..."); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, &format!("...but `{}` is only valid for ", self.tcx.local_var_name_str(upvar_id.var_id)), sup, ""); + err.emit(); } infer::InfStackClosure(span) => { - span_err!(self.tcx.sess, span, E0314, + let mut err = struct_span_err!(self.tcx.sess, span, E0314, "closure outlives stack frame"); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "...the closure must be valid for ", sub, "..."); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "...but the closure's stack frame is only valid for ", sup, ""); + err.emit(); } infer::InvokeClosure(span) => { - span_err!(self.tcx.sess, span, E0315, + let mut err = struct_span_err!(self.tcx.sess, span, E0315, "cannot invoke closure outside of its lifetime"); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "the closure is only valid for ", sup, ""); + err.emit(); } infer::DerefPointer(span) => { - span_err!(self.tcx.sess, span, E0473, + let mut err = struct_span_err!(self.tcx.sess, span, E0473, "dereference of reference outside its lifetime"); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "the reference is only valid for ", sup, ""); + err.emit(); } infer::FreeVariable(span, id) => { - span_err!(self.tcx.sess, span, E0474, + let mut err = struct_span_err!(self.tcx.sess, span, E0474, "captured variable `{}` does not outlive the enclosing closure", self.tcx.local_var_name_str(id)); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "captured variable is valid for ", sup, ""); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "closure is valid for ", sub, ""); + err.emit(); } infer::IndexSlice(span) => { - span_err!(self.tcx.sess, span, E0475, + let mut err = struct_span_err!(self.tcx.sess, span, E0475, "index of slice outside its lifetime"); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "the slice is only valid for ", sup, ""); + err.emit(); } infer::RelateObjectBound(span) => { - span_err!(self.tcx.sess, span, E0476, + let mut err = struct_span_err!(self.tcx.sess, span, E0476, "lifetime of the source pointer does not outlive \ lifetime bound of the object type"); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "object type is valid for ", sub, ""); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "source pointer is only valid for ", sup, ""); + err.emit(); } infer::RelateParamBound(span, ty) => { - span_err!(self.tcx.sess, span, E0477, + let mut err = struct_span_err!(self.tcx.sess, span, E0477, "the type `{}` does not fulfill the required lifetime", self.ty_to_string(ty)); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "type must outlive ", sub, ""); + err.emit(); } infer::RelateRegionParamBound(span) => { - span_err!(self.tcx.sess, span, E0478, + let mut err = struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied"); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "lifetime parameter instantiated with ", sup, ""); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "but lifetime parameter must outlive ", sub, ""); + err.emit(); } infer::RelateDefaultParamBound(span, ty) => { - span_err!(self.tcx.sess, span, E0479, + let mut err = struct_span_err!(self.tcx.sess, span, E0479, "the type `{}` (provided as the value of \ a type parameter) is not valid at this point", self.ty_to_string(ty)); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "type must outlive ", sub, ""); + err.emit(); } infer::CallRcvr(span) => { - span_err!(self.tcx.sess, span, E0480, + let mut err = struct_span_err!(self.tcx.sess, span, E0480, "lifetime of method receiver does not outlive \ the method call"); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "the receiver is only valid for ", sup, ""); + err.emit(); } infer::CallArg(span) => { - span_err!(self.tcx.sess, span, E0481, + let mut err = struct_span_err!(self.tcx.sess, span, E0481, "lifetime of function argument does not outlive \ the function call"); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "the function argument is only valid for ", sup, ""); + err.emit(); } infer::CallReturn(span) => { - span_err!(self.tcx.sess, span, E0482, + let mut err = struct_span_err!(self.tcx.sess, span, E0482, "lifetime of return value does not outlive \ the function call"); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "the return value is only valid for ", sup, ""); + err.emit(); } infer::Operand(span) => { - span_err!(self.tcx.sess, span, E0483, + let mut err = struct_span_err!(self.tcx.sess, span, E0483, "lifetime of operand does not outlive \ the operation"); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "the operand is only valid for ", sup, ""); + err.emit(); } infer::AddrOf(span) => { - span_err!(self.tcx.sess, span, E0484, + let mut err = struct_span_err!(self.tcx.sess, span, E0484, "reference is not valid at the time of borrow"); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "the borrow is only valid for ", sup, ""); + err.emit(); } infer::AutoBorrow(span) => { - span_err!(self.tcx.sess, span, E0485, + let mut err = struct_span_err!(self.tcx.sess, span, E0485, "automatically reference is not valid \ at the time of borrow"); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "the automatic borrow is only valid for ", sup, ""); + err.emit(); } infer::ExprTypeIsNotInScope(t, span) => { - span_err!(self.tcx.sess, span, E0486, + let mut err = struct_span_err!(self.tcx.sess, span, E0486, "type of expression contains references \ that are not valid during the expression: `{}`", self.ty_to_string(t)); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "type is only valid for ", sup, ""); + err.emit(); } infer::SafeDestructor(span) => { - span_err!(self.tcx.sess, span, E0487, + let mut err = struct_span_err!(self.tcx.sess, span, E0487, "unsafe use of destructor: destructor might be called \ while references are dead"); // FIXME (22171): terms "super/subregion" are suboptimal - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "superregion: ", sup, ""); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "subregion: ", sub, ""); + err.emit(); } infer::BindingTypeIsNotValidAtDecl(span) => { - span_err!(self.tcx.sess, span, E0488, + let mut err = struct_span_err!(self.tcx.sess, span, E0488, "lifetime of variable does not enclose its declaration"); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "the variable is only valid for ", sup, ""); + err.emit(); } infer::ParameterInScope(_, span) => { - span_err!(self.tcx.sess, span, E0489, + let mut err = struct_span_err!(self.tcx.sess, span, E0489, "type/lifetime parameter not in scope here"); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "the parameter is only valid for ", sub, ""); + err.emit(); } infer::DataBorrowed(ty, span) => { - span_err!(self.tcx.sess, span, E0490, + let mut err = struct_span_err!(self.tcx.sess, span, E0490, "a value of type `{}` is borrowed for too long", self.ty_to_string(ty)); - self.tcx.note_and_explain_region("the type is valid for ", sub, ""); - self.tcx.note_and_explain_region("but the borrow lasts for ", sup, ""); + self.tcx.note_and_explain_region(&mut err, "the type is valid for ", sub, ""); + self.tcx.note_and_explain_region(&mut err, "but the borrow lasts for ", sup, ""); + err.emit(); } infer::ReferenceOutlivesReferent(ty, span) => { - span_err!(self.tcx.sess, span, E0491, + let mut err = struct_span_err!(self.tcx.sess, span, E0491, "in type `{}`, reference has a longer lifetime \ than the data it references", self.ty_to_string(ty)); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "the pointer is valid for ", sub, ""); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "but the referenced data is only valid for ", sup, ""); + err.emit(); } } } @@ -884,37 +942,42 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { sub_region: Region, sup_origin: SubregionOrigin<'tcx>, sup_region: Region) { - self.report_inference_failure(var_origin); + let mut err = self.report_inference_failure(var_origin); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "first, the lifetime cannot outlive ", sup_region, "..."); - self.note_region_origin(&sup_origin); + self.note_region_origin(&mut err, &sup_origin); - self.tcx.note_and_explain_region( + self.tcx.note_and_explain_region(&mut err, "but, the lifetime must be valid for ", sub_region, "..."); - self.note_region_origin(&sub_origin); + self.note_region_origin(&mut err, &sub_origin); + err.emit(); } fn report_processed_errors(&self, var_origins: &[RegionVariableOrigin], trace_origins: &[(TypeTrace<'tcx>, TypeError<'tcx>)], same_regions: &[SameRegions]) { - for vo in var_origins { - self.report_inference_failure(vo.clone()); + for (i, vo) in var_origins.iter().enumerate() { + let mut err = self.report_inference_failure(vo.clone()); + if i == var_origins.len() - 1 { + self.give_suggestion(&mut err, same_regions); + } + err.emit(); } - self.give_suggestion(same_regions); + for &(ref trace, ref terr) in trace_origins { self.report_and_explain_type_error(trace.clone(), terr); } } - fn give_suggestion(&self, same_regions: &[SameRegions]) { + fn give_suggestion(&self, err: &mut DiagnosticBuilder, same_regions: &[SameRegions]) { let scope_id = same_regions[0].scope_id; let parent = self.tcx.map.get_parent(scope_id); let parent_node = self.tcx.map.find(parent); @@ -968,7 +1031,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { let rebuilder = Rebuilder::new(self.tcx, fn_decl, expl_self, generics, same_regions, &life_giver); let (fn_decl, expl_self, generics) = rebuilder.rebuild(); - self.give_expl_lifetime_param(&fn_decl, unsafety, constness, name, + self.give_expl_lifetime_param(err, &fn_decl, unsafety, constness, name, expl_self.as_ref(), &generics, span); } } @@ -1520,6 +1583,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { fn give_expl_lifetime_param(&self, + err: &mut DiagnosticBuilder, decl: &hir::FnDecl, unsafety: hir::Unsafety, constness: hir::Constness, @@ -1531,11 +1595,12 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { opt_explicit_self, generics); let msg = format!("consider using an explicit lifetime \ parameter as shown: {}", suggested_fn); - self.tcx.sess.span_help(span, &msg[..]); + err.span_help(span, &msg[..]); } fn report_inference_failure(&self, - var_origin: RegionVariableOrigin) { + var_origin: RegionVariableOrigin) + -> DiagnosticBuilder<'tcx> { let br_string = |br: ty::BoundRegion| { let mut s = br.to_string(); if !s.is_empty() { @@ -1574,13 +1639,13 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { } }; - span_err!(self.tcx.sess, var_origin.span(), E0495, + struct_span_err!(self.tcx.sess, var_origin.span(), E0495, "cannot infer an appropriate lifetime{} \ due to conflicting requirements", - var_description); + var_description) } - fn note_region_origin(&self, origin: &SubregionOrigin<'tcx>) { + fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) { match *origin { infer::Subtype(ref trace) => { let desc = match trace.origin { @@ -1622,7 +1687,7 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { match self.values_str(&trace.values) { Some(values_str) => { - self.tcx.sess.span_note( + err.span_note( trace.origin.span(), &format!("...so that {} ({})", desc, values_str)); @@ -1632,130 +1697,130 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { // all, since it is derived, but that would // require more refactoring than I feel like // doing right now. - nmatsakis - self.tcx.sess.span_note( + err.span_note( trace.origin.span(), &format!("...so that {}", desc)); } } } infer::Reborrow(span) => { - self.tcx.sess.span_note( + err.span_note( span, "...so that reference does not outlive \ borrowed content"); } infer::ReborrowUpvar(span, ref upvar_id) => { - self.tcx.sess.span_note( + err.span_note( span, &format!( "...so that closure can access `{}`", self.tcx.local_var_name_str(upvar_id.var_id) - .to_string())) + .to_string())); } infer::InfStackClosure(span) => { - self.tcx.sess.span_note( + err.span_note( span, "...so that closure does not outlive its stack frame"); } infer::InvokeClosure(span) => { - self.tcx.sess.span_note( + err.span_note( span, "...so that closure is not invoked outside its lifetime"); } infer::DerefPointer(span) => { - self.tcx.sess.span_note( + err.span_note( span, "...so that pointer is not dereferenced \ outside its lifetime"); } infer::FreeVariable(span, id) => { - self.tcx.sess.span_note( + err.span_note( span, &format!("...so that captured variable `{}` \ does not outlive the enclosing closure", self.tcx.local_var_name_str(id))); } infer::IndexSlice(span) => { - self.tcx.sess.span_note( + err.span_note( span, "...so that slice is not indexed outside the lifetime"); } infer::RelateObjectBound(span) => { - self.tcx.sess.span_note( + err.span_note( span, "...so that it can be closed over into an object"); } infer::CallRcvr(span) => { - self.tcx.sess.span_note( + err.span_note( span, "...so that method receiver is valid for the method call"); } infer::CallArg(span) => { - self.tcx.sess.span_note( + err.span_note( span, "...so that argument is valid for the call"); } infer::CallReturn(span) => { - self.tcx.sess.span_note( + err.span_note( span, "...so that return value is valid for the call"); } infer::Operand(span) => { - self.tcx.sess.span_note( + err.span_note( span, "...so that operand is valid for operation"); } infer::AddrOf(span) => { - self.tcx.sess.span_note( + err.span_note( span, "...so that reference is valid \ at the time of borrow"); } infer::AutoBorrow(span) => { - self.tcx.sess.span_note( + err.span_note( span, "...so that auto-reference is valid \ at the time of borrow"); } infer::ExprTypeIsNotInScope(t, span) => { - self.tcx.sess.span_note( + err.span_note( span, &format!("...so type `{}` of expression is valid during the \ expression", self.ty_to_string(t))); } infer::BindingTypeIsNotValidAtDecl(span) => { - self.tcx.sess.span_note( + err.span_note( span, "...so that variable is valid at time of its declaration"); } infer::ParameterInScope(_, span) => { - self.tcx.sess.span_note( + err.span_note( span, "...so that a type/lifetime parameter is in scope here"); } infer::DataBorrowed(ty, span) => { - self.tcx.sess.span_note( + err.span_note( span, &format!("...so that the type `{}` is not borrowed for too long", self.ty_to_string(ty))); } infer::ReferenceOutlivesReferent(ty, span) => { - self.tcx.sess.span_note( + err.span_note( span, &format!("...so that the reference type `{}` \ does not outlive the data it points at", self.ty_to_string(ty))); } infer::RelateParamBound(span, t) => { - self.tcx.sess.span_note( + err.span_note( span, &format!("...so that the type `{}` \ will meet its required lifetime bounds", self.ty_to_string(t))); } infer::RelateDefaultParamBound(span, t) => { - self.tcx.sess.span_note( + err.span_note( span, &format!("...so that type parameter \ instantiated with `{}`, \ @@ -1763,16 +1828,16 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { self.ty_to_string(t))); } infer::RelateRegionParamBound(span) => { - self.tcx.sess.span_note( + err.span_note( span, "...so that the declared lifetime parameter bounds \ are satisfied"); } infer::SafeDestructor(span) => { - self.tcx.sess.span_note( + err.span_note( span, "...so that references are valid when the destructor \ - runs") + runs"); } } } diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index d0ffed56635f7..81d3d429f26b8 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -40,6 +40,7 @@ use std::fmt; use syntax::ast; use syntax::codemap; use syntax::codemap::{Span, DUMMY_SP}; +use syntax::errors::DiagnosticBuilder; use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap}; use self::combine::CombineFields; @@ -1269,19 +1270,43 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { sp: Span, mk_msg: M, actual_ty: String, - err: Option<&TypeError<'tcx>>) where - M: FnOnce(Option, String) -> String, + err: Option<&TypeError<'tcx>>) + where M: FnOnce(Option, String) -> String, { self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err) } + pub fn type_error_struct_str(&self, + sp: Span, + mk_msg: M, + actual_ty: String, + err: Option<&TypeError<'tcx>>) + -> Option> + where M: FnOnce(Option, String) -> String, + { + self.type_error_struct_str_with_expected(sp, mk_msg, None, actual_ty, err) + } + pub fn type_error_message_str_with_expected(&self, sp: Span, mk_msg: M, expected_ty: Option>, actual_ty: String, - err: Option<&TypeError<'tcx>>) where - M: FnOnce(Option, String) -> String, + err: Option<&TypeError<'tcx>>) + where M: FnOnce(Option, String) -> String, + { + self.type_error_struct_str_with_expected(sp, mk_msg, expected_ty, actual_ty, err) + .map(|mut e| e.emit()); + } + + pub fn type_error_struct_str_with_expected(&self, + sp: Span, + mk_msg: M, + expected_ty: Option>, + actual_ty: String, + err: Option<&TypeError<'tcx>>) + -> Option> + where M: FnOnce(Option, String) -> String, { debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty); @@ -1292,13 +1317,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { format!(" ({})", t_err) }); - self.tcx.sess.span_err(sp, &format!("{}{}", + let mut db = self.tcx.sess.struct_span_err(sp, &format!("{}{}", mk_msg(resolved_expected.map(|t| self.ty_to_string(t)), actual_ty), error_str)); if let Some(err) = err { - self.tcx.note_and_explain_type_err(err, sp) + self.tcx.note_and_explain_type_err(&mut db, err, sp); } + Some(db) + } else { + None } } @@ -1306,19 +1334,30 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { sp: Span, mk_msg: M, actual_ty: Ty<'tcx>, - err: Option<&TypeError<'tcx>>) where - M: FnOnce(String) -> String, + err: Option<&TypeError<'tcx>>) + where M: FnOnce(String) -> String, + { + self.type_error_struct(sp, mk_msg, actual_ty, err).map(|mut e| e.emit()); + } + + pub fn type_error_struct(&self, + sp: Span, + mk_msg: M, + actual_ty: Ty<'tcx>, + err: Option<&TypeError<'tcx>>) + -> Option> + where M: FnOnce(String) -> String, { let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); // Don't report an error if actual type is TyError. if actual_ty.references_error() { - return; + return None; } - self.type_error_message_str(sp, + self.type_error_struct_str(sp, move |_e, a| { mk_msg(a) }, - self.ty_to_string(actual_ty), err); + self.ty_to_string(actual_ty), err) } pub fn report_mismatched_types(&self, diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 540af4ae00165..29299f01ed36f 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1500,7 +1500,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { }, _ => false }; - span_err!(self.ir.tcx.sess, sp, E0269, "not all control paths return a value"); + let mut err = struct_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(), @@ -1510,9 +1513,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hi: original_span.hi, expn_id: original_span.expn_id }; - self.ir.tcx.sess.span_help( - span_semicolon, "consider removing this semicolon:"); + err.span_help(span_semicolon, "consider removing this semicolon:"); } + err.emit(); } } ty::FnDiverging diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 9b133c5401519..2c74f3a82e414 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -345,25 +345,25 @@ impl ShadowKind { } } -fn signal_shadowing_problem( - sess: &Session, name: ast::Name, orig: Original, shadower: Shadower) { - if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) { +fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, shadower: Shadower) { + let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) { // lifetime/lifetime shadowing is an error - span_err!(sess, shadower.span, E0496, - "{} name `{}` shadows a \ - {} name that is already in scope", - shadower.kind.desc(), name, orig.kind.desc()); + struct_span_err!(sess, shadower.span, E0496, + "{} name `{}` shadows a \ + {} name that is already in scope", + shadower.kind.desc(), name, orig.kind.desc()) } else { // shadowing involving a label is only a warning, due to issues with // labels and lifetimes not being macro-hygienic. - sess.span_warn(shadower.span, - &format!("{} name `{}` shadows a \ - {} name that is already in scope", - shadower.kind.desc(), name, orig.kind.desc())); - } - sess.span_note(orig.span, - &format!("shadowed {} `{}` declared here", - orig.kind.desc(), name)); + sess.struct_span_warn(shadower.span, + &format!("{} name `{}` shadows a \ + {} name that is already in scope", + shadower.kind.desc(), name, orig.kind.desc())) + }; + err.span_note(orig.span, + &format!("shadowed {} `{}` declared here", + orig.kind.desc(), name)); + err.emit(); } // Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index a41ee51fb5546..f6af680d441eb 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -394,17 +394,19 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { // This is an 'unmarked' API, which should not exist // in the standard library. if self.tcx.sess.features.borrow().unmarked_api { - self.tcx.sess.span_warn(span, "use of unmarked library feature"); - self.tcx.sess.span_note(span, "this is either a bug in the library you are \ + self.tcx.sess.struct_span_warn(span, "use of unmarked library feature") + .span_note(span, "this is either a bug in the library you are \ using or a bug in the compiler - please \ - report it in both places"); + report it in both places") + .emit() } else { - self.tcx.sess.span_err(span, "use of unmarked library feature"); - self.tcx.sess.span_note(span, "this is either a bug in the library you are \ + self.tcx.sess.struct_span_err(span, "use of unmarked library feature") + .span_note(span, "this is either a bug in the library you are \ using or a bug in the compiler - please \ - report it in both places"); - self.tcx.sess.span_note(span, "use #![feature(unmarked_api)] in the \ - crate attributes to override this"); + report it in both places") + .span_note(span, "use #![feature(unmarked_api)] in the \ + crate attributes to override this") + .emit() } } } diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index 9cf8043be3ba1..9193b1a09f9fa 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -31,8 +31,9 @@ use middle::ty::fold::TypeFoldable; use util::nodemap::{FnvHashMap, FnvHashSet}; use std::fmt; -use syntax::codemap::Span; use syntax::attr::{AttributeMethods, AttrMetaMethods}; +use syntax::codemap::Span; +use syntax::errors::DiagnosticBuilder; #[derive(Debug, PartialEq, Eq, Hash)] pub struct TraitErrorKey<'tcx> { @@ -94,12 +95,12 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, // then $X will be unified with TyError, but the error still needs to be // reported. if !infcx.tcx.sess.has_errors() || !predicate.references_error() { - span_err!( - infcx.tcx.sess, obligation.cause.span, E0271, + let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0271, "type mismatch resolving `{}`: {}", predicate, error.err); - note_obligation_cause(infcx, obligation); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); } } @@ -186,14 +187,15 @@ pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, { let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate); - span_err!(infcx.tcx.sess, obligation.cause.span, E0275, - "overflow evaluating the requirement `{}`", - predicate); + let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0275, + "overflow evaluating the requirement `{}`", + predicate); - suggest_new_overflow_limit(infcx.tcx, obligation.cause.span); + suggest_new_overflow_limit(infcx.tcx, &mut err, obligation.cause.span); - note_obligation_cause(infcx, obligation); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); infcx.tcx.sess.abort_if_errors(); unreachable!(); } @@ -218,7 +220,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, if !infcx.tcx.sess.has_errors() || !trait_predicate.references_error() { let trait_ref = trait_predicate.to_poly_trait_ref(); - span_err!( + let mut err = struct_span_err!( infcx.tcx.sess, obligation.cause.span, E0277, "the trait `{}` is not implemented for the type `{}`", trait_ref, trait_ref.self_ty()); @@ -228,9 +230,10 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, let custom_note = report_on_unimplemented(infcx, &trait_ref.0, obligation.cause.span); if let Some(s) = custom_note { - infcx.tcx.sess.fileline_note(obligation.cause.span, &s); + err.fileline_note(obligation.cause.span, &s); } - note_obligation_cause(infcx, obligation); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); } } @@ -238,44 +241,48 @@ 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).err().unwrap(); - span_err!( + let mut err = struct_span_err!( infcx.tcx.sess, obligation.cause.span, E0278, "the requirement `{}` is not satisfied (`{}`)", predicate, err); - note_obligation_cause(infcx, obligation); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); } ty::Predicate::RegionOutlives(ref predicate) => { let predicate = infcx.resolve_type_vars_if_possible(predicate); let err = infcx.region_outlives_predicate(obligation.cause.span, &predicate).err().unwrap(); - span_err!( + let mut err = struct_span_err!( infcx.tcx.sess, obligation.cause.span, E0279, "the requirement `{}` is not satisfied (`{}`)", predicate, err); - note_obligation_cause(infcx, obligation); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); } ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate); - span_err!( + let mut err = struct_span_err!( infcx.tcx.sess, obligation.cause.span, E0280, "the requirement `{}` is not satisfied", predicate); - note_obligation_cause(infcx, obligation); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); } ty::Predicate::ObjectSafe(trait_def_id) => { let violations = object_safety_violations( infcx.tcx, trait_def_id); - report_object_safety_error(infcx.tcx, - obligation.cause.span, - trait_def_id, - violations); - note_obligation_cause(infcx, obligation); + let mut err = report_object_safety_error(infcx.tcx, + obligation.cause.span, + trait_def_id, + violations); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); } ty::Predicate::WellFormed(ty) => { @@ -296,7 +303,7 @@ 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 !actual_trait_ref.self_ty().references_error() { - span_err!( + let mut err = struct_span_err!( infcx.tcx.sess, obligation.cause.span, E0281, "type mismatch: the type `{}` implements the trait `{}`, \ but the trait `{}` is required ({})", @@ -304,14 +311,17 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, expected_trait_ref, actual_trait_ref, e); - note_obligation_cause(infcx, obligation); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); } } TraitNotObjectSafe(did) => { let violations = object_safety_violations(infcx.tcx, did); - report_object_safety_error(infcx.tcx, obligation.cause.span, did, violations); - note_obligation_cause(infcx, obligation); + let mut err = report_object_safety_error(infcx.tcx, obligation.cause.span, did, + violations); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); } } } @@ -320,8 +330,9 @@ pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, trait_def_id: DefId, violations: Vec) + -> DiagnosticBuilder<'tcx> { - span_err!( + let mut err = struct_span_err!( tcx.sess, span, E0038, "the trait `{}` cannot be made into an object", tcx.item_path_str(trait_def_id)); @@ -333,13 +344,13 @@ pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>, } match violation { ObjectSafetyViolation::SizedSelf => { - tcx.sess.fileline_note( + err.fileline_note( span, "the trait cannot require that `Self : Sized`"); } ObjectSafetyViolation::SupertraitSelf => { - tcx.sess.fileline_note( + err.fileline_note( span, "the trait cannot use `Self` as a type parameter \ in the supertrait listing"); @@ -347,7 +358,7 @@ pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>, ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => { - tcx.sess.fileline_note( + err.fileline_note( span, &format!("method `{}` has no receiver", method.name)); @@ -355,7 +366,7 @@ pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>, ObjectSafetyViolation::Method(method, MethodViolationCode::ReferencesSelf) => { - tcx.sess.fileline_note( + err.fileline_note( span, &format!("method `{}` references the `Self` type \ in its arguments or return type", @@ -364,13 +375,14 @@ pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>, ObjectSafetyViolation::Method(method, MethodViolationCode::Generic) => { - tcx.sess.fileline_note( + err.fileline_note( span, &format!("method `{}` has generic type parameters", method.name)); } } } + err } pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, @@ -424,10 +436,12 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, { need_type_info(infcx, obligation.cause.span, self_ty); } else { - span_err!(infcx.tcx.sess, obligation.cause.span, E0283, - "type annotations required: cannot resolve `{}`", - predicate); - note_obligation_cause(infcx, obligation); + let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0283, + "type annotations required: \ + cannot resolve `{}`", + predicate); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); } } } @@ -443,10 +457,11 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, _ => { if !infcx.tcx.sess.has_errors() { - span_err!(infcx.tcx.sess, obligation.cause.span, E0284, - "type annotations required: cannot resolve `{}`", - predicate); - note_obligation_cause(infcx, obligation); + let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0284, + "type annotations required: cannot resolve `{}`", + predicate); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); } } } @@ -463,16 +478,19 @@ fn need_type_info<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, } fn note_obligation_cause<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, + err: &mut DiagnosticBuilder, obligation: &Obligation<'tcx, T>) where T: fmt::Display { note_obligation_cause_code(infcx, + err, &obligation.predicate, obligation.cause.span, &obligation.cause.code); } fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, + err: &mut DiagnosticBuilder, predicate: &T, cause_span: Span, cause_code: &ObligationCauseCode<'tcx>) @@ -482,59 +500,59 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, match *cause_code { ObligationCauseCode::MiscObligation => { } ObligationCauseCode::SliceOrArrayElem => { - tcx.sess.fileline_note( + err.fileline_note( cause_span, "slice and array elements must have `Sized` type"); } ObligationCauseCode::ProjectionWf(data) => { - tcx.sess.fileline_note( + err.fileline_note( cause_span, &format!("required so that the projection `{}` is well-formed", data)); } ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { - tcx.sess.fileline_note( + err.fileline_note( cause_span, &format!("required so that reference `{}` does not outlive its referent", ref_ty)); } ObligationCauseCode::ItemObligation(item_def_id) => { let item_name = tcx.item_path_str(item_def_id); - tcx.sess.fileline_note( + err.fileline_note( cause_span, &format!("required by `{}`", item_name)); } ObligationCauseCode::ObjectCastObligation(object_ty) => { - tcx.sess.fileline_note( + err.fileline_note( cause_span, &format!( "required for the cast to the object type `{}`", infcx.ty_to_string(object_ty))); } ObligationCauseCode::RepeatVec => { - tcx.sess.fileline_note( + err.fileline_note( cause_span, "the `Copy` trait is required because the \ repeated element will be copied"); } ObligationCauseCode::VariableType(_) => { - tcx.sess.fileline_note( + err.fileline_note( cause_span, "all local variables must have a statically known size"); } ObligationCauseCode::ReturnType => { - tcx.sess.fileline_note( + err.fileline_note( cause_span, "the return type of a function must have a \ statically known size"); } ObligationCauseCode::AssignmentLhsSized => { - tcx.sess.fileline_note( + err.fileline_note( cause_span, "the left-hand-side of an assignment must have a statically known size"); } ObligationCauseCode::StructInitializerSized => { - tcx.sess.fileline_note( + err.fileline_note( cause_span, "structs must have a statically known size to be initialized"); } @@ -542,7 +560,7 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap(); let trait_name = tcx.item_path_str(def_id); let name = tcx.local_var_name_str(var_id); - tcx.sess.fileline_note( + err.fileline_note( cause_span, &format!("the closure that captures `{}` requires that all captured variables \ implement the trait `{}`", @@ -550,37 +568,45 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, trait_name)); } ObligationCauseCode::FieldSized => { - tcx.sess.fileline_note( + err.fileline_note( cause_span, "only the last field of a struct or enum variant \ may have a dynamically sized type"); } ObligationCauseCode::SharedStatic => { - tcx.sess.fileline_note( + err.fileline_note( cause_span, "shared static variables must have a type that implements `Sync`"); } ObligationCauseCode::BuiltinDerivedObligation(ref data) => { let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref); - tcx.sess.fileline_note( + err.fileline_note( cause_span, &format!("required because it appears within the type `{}`", parent_trait_ref.0.self_ty())); let parent_predicate = parent_trait_ref.to_predicate(); - note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code); + note_obligation_cause_code(infcx, + err, + &parent_predicate, + cause_span, + &*data.parent_code); } ObligationCauseCode::ImplDerivedObligation(ref data) => { let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref); - tcx.sess.fileline_note( + err.fileline_note( cause_span, &format!("required because of the requirements on the impl of `{}` for `{}`", parent_trait_ref, parent_trait_ref.0.self_ty())); let parent_predicate = parent_trait_ref.to_predicate(); - note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code); + note_obligation_cause_code(infcx, + err, + &parent_predicate, + cause_span, + &*data.parent_code); } ObligationCauseCode::CompareImplMethodObligation => { - tcx.sess.fileline_note( + err.fileline_note( cause_span, &format!("the requirement `{}` appears on the impl method \ but not on the corresponding trait method", @@ -589,10 +615,10 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, } } -fn suggest_new_overflow_limit(tcx: &ty::ctxt, span: Span) { +fn suggest_new_overflow_limit(tcx: &ty::ctxt, err:&mut DiagnosticBuilder, span: Span) { let current_limit = tcx.sess.recursion_limit.get(); let suggested_limit = current_limit * 2; - tcx.sess.fileline_note( + err.fileline_note( span, &format!( "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", diff --git a/src/librustc/middle/ty/error.rs b/src/librustc/middle/ty/error.rs index d9033eaa29f6b..ab48fd7fb8665 100644 --- a/src/librustc/middle/ty/error.rs +++ b/src/librustc/middle/ty/error.rs @@ -17,6 +17,7 @@ use std::fmt; use syntax::abi; use syntax::ast::{self, Name}; use syntax::codemap::Span; +use syntax::errors::DiagnosticBuilder; use rustc_front::hir; @@ -252,27 +253,30 @@ impl<'tcx> ty::TyS<'tcx> { } impl<'tcx> ty::ctxt<'tcx> { - pub fn note_and_explain_type_err(&self, err: &TypeError<'tcx>, sp: Span) { + pub fn note_and_explain_type_err(&self, + db: &mut DiagnosticBuilder, + err: &TypeError<'tcx>, + sp: Span) { use self::TypeError::*; match err.clone() { RegionsDoesNotOutlive(subregion, superregion) => { - self.note_and_explain_region("", subregion, "..."); - self.note_and_explain_region("...does not necessarily outlive ", + self.note_and_explain_region(db, "", subregion, "..."); + self.note_and_explain_region(db, "...does not necessarily outlive ", superregion, ""); } RegionsNotSame(region1, region2) => { - self.note_and_explain_region("", region1, "..."); - self.note_and_explain_region("...is not the same lifetime as ", + self.note_and_explain_region(db, "", region1, "..."); + self.note_and_explain_region(db, "...is not the same lifetime as ", region2, ""); } RegionsNoOverlap(region1, region2) => { - self.note_and_explain_region("", region1, "..."); - self.note_and_explain_region("...does not overlap ", + self.note_and_explain_region(db, "", region1, "..."); + self.note_and_explain_region(db, "...does not overlap ", region2, ""); } RegionsInsufficientlyPolymorphic(_, conc_region) => { - self.note_and_explain_region("concrete lifetime that was found is ", + self.note_and_explain_region(db, "concrete lifetime that was found is ", conc_region, ""); } RegionsOverlyPolymorphic(_, ty::ReVar(_)) => { @@ -280,42 +284,40 @@ impl<'tcx> ty::ctxt<'tcx> { // inference variables, it's not very illuminating. } RegionsOverlyPolymorphic(_, conc_region) => { - self.note_and_explain_region("expected concrete lifetime is ", + self.note_and_explain_region(db, "expected concrete lifetime is ", conc_region, ""); } Sorts(values) => { let expected_str = values.expected.sort_string(self); let found_str = values.found.sort_string(self); if expected_str == found_str && expected_str == "closure" { - self.sess.span_note(sp, + db.span_note(sp, "no two closures, even if identical, have the same type"); - self.sess.span_help(sp, + db.span_help(sp, "consider boxing your closure and/or using it as a trait object"); } }, TyParamDefaultMismatch(values) => { let expected = values.expected; let found = values.found; - self.sess.span_note(sp, - &format!("conflicting type parameter defaults `{}` and `{}`", - expected.ty, - found.ty)); + db.span_note(sp, &format!("conflicting type parameter defaults `{}` and `{}`", + expected.ty, + found.ty)); match self.map.as_local_node_id(expected.def_id) .and_then(|node_id| self.map.opt_span(node_id)) { Some(span) => { - self.sess.span_note(span, "a default was defined here..."); + db.span_note(span, "a default was defined here..."); } None => { - self.sess.note( - &format!("a default is defined on `{}`", - self.item_path_str(expected.def_id))); + db.note(&format!("a default is defined on `{}`", + self.item_path_str(expected.def_id))); } } - self.sess.span_note( + db.span_note( expected.origin_span, "...that was applied to an unconstrained type variable here"); @@ -324,18 +326,16 @@ impl<'tcx> ty::ctxt<'tcx> { .and_then(|node_id| self.map.opt_span(node_id)) { Some(span) => { - self.sess.span_note(span, "a second default was defined here..."); + db.span_note(span, "a second default was defined here..."); } None => { - self.sess.note( - &format!("a second default is defined on `{}`", - self.item_path_str(found.def_id))); + db.note(&format!("a second default is defined on `{}`", + self.item_path_str(found.def_id))); } } - self.sess.span_note( - found.origin_span, - "...that also applies to the same type variable here"); + db.span_note(found.origin_span, + "...that also applies to the same type variable here"); } _ => {} } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 4fec05ed594b3..80b4c1916a816 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -80,52 +80,58 @@ pub struct Session { } impl Session { - pub fn struct_span_warn<'a, 'b>(&'a self, - sp: Span, - msg: &'b str) - -> Box> { + pub fn struct_span_warn<'a>(&'a self, + sp: Span, + msg: &str) + -> DiagnosticBuilder<'a> { self.diagnostic().struct_span_warn(sp, msg) } - pub fn struct_span_warn_with_code<'a, 'b>(&'a self, - sp: Span, - msg: &'b str, - code: &str) - -> Box> { + pub fn struct_span_warn_with_code<'a>(&'a self, + sp: Span, + msg: &str, + code: &str) + -> DiagnosticBuilder<'a> { self.diagnostic().struct_span_warn_with_code(sp, msg, code) } - pub fn struct_warn<'a, 'b>(&'a self, msg: &'b str) -> Box> { + pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { self.diagnostic().struct_warn(msg) } - pub fn struct_span_err<'a, 'b>(&'a self, - sp: Span, - msg: &'b str) - -> Box> { - self.diagnostic().struct_span_err(sp, msg) + pub fn struct_span_err<'a>(&'a self, + sp: Span, + msg: &str) + -> DiagnosticBuilder<'a> { + match split_msg_into_multilines(msg) { + Some(ref msg) => self.diagnostic().struct_span_err(sp, msg), + None => self.diagnostic().struct_span_err(sp, msg), + } } - pub fn struct_span_err_with_code<'a, 'b>(&'a self, - sp: Span, - msg: &'b str, - code: &str) - -> Box> { - self.diagnostic().struct_span_err_with_code(sp, msg, code) + pub fn struct_span_err_with_code<'a>(&'a self, + sp: Span, + msg: &str, + code: &str) + -> DiagnosticBuilder<'a> { + match split_msg_into_multilines(msg) { + Some(ref msg) => self.diagnostic().struct_span_err_with_code(sp, msg, code), + None => self.diagnostic().struct_span_err_with_code(sp, msg, code), + } } - pub fn struct_err<'a, 'b>(&'a self, msg: &'b str) -> Box> { + pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { self.diagnostic().struct_err(msg) } - pub fn struct_span_fatal<'a, 'b>(&'a self, - sp: Span, - msg: &'b str) - -> Box> { + pub fn struct_span_fatal<'a>(&'a self, + sp: Span, + msg: &str) + -> DiagnosticBuilder<'a> { self.diagnostic().struct_span_fatal(sp, msg) } - pub fn struct_span_fatal_with_code<'a, 'b>(&'a self, - sp: Span, - msg: &'b str, - code: &str) - -> Box> { + pub fn struct_span_fatal_with_code<'a>(&'a self, + sp: Span, + msg: &str, + code: &str) + -> DiagnosticBuilder<'a> { self.diagnostic().struct_span_fatal_with_code(sp, msg, code) } - pub fn struct_fatal<'a, 'b>(&'a self, msg: &'b str) -> Box> { + pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { self.diagnostic().struct_fatal(msg) } @@ -147,13 +153,13 @@ impl Session { } pub fn span_err(&self, sp: Span, msg: &str) { match split_msg_into_multilines(msg) { - Some(msg) => self.diagnostic().span_err(sp, &msg[..]), + Some(msg) => self.diagnostic().span_err(sp, &msg), None => self.diagnostic().span_err(sp, msg) } } pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) { match split_msg_into_multilines(msg) { - Some(msg) => self.diagnostic().span_err_with_code(sp, &msg[..], code), + Some(msg) => self.diagnostic().span_err_with_code(sp, &msg, code), None => self.diagnostic().span_err_with_code(sp, msg, code) } } @@ -209,6 +215,12 @@ impl Session { pub fn bug(&self, msg: &str) -> ! { self.diagnostic().bug(msg) } + pub fn note_without_error(&self, msg: &str) { + self.diagnostic().note_without_error(msg) + } + pub fn span_note_without_error(&self, sp: Span, msg: &str) { + self.diagnostic().span_note_without_error(sp, msg) + } pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! { self.diagnostic().span_unimpl(sp, msg) } diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 3f48051029d9d..df181aec4ea4c 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -465,44 +465,44 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { format!("`{}`", ol) }; - match (new_loan.kind, old_loan.kind) { + let mut err = match (new_loan.kind, old_loan.kind) { (ty::MutBorrow, ty::MutBorrow) => { - span_err!(self.bccx, new_loan.span, E0499, - "cannot borrow `{}`{} as mutable \ - more than once at a time", - nl, new_loan_msg); + struct_span_err!(self.bccx, new_loan.span, E0499, + "cannot borrow `{}`{} as mutable \ + more than once at a time", + nl, new_loan_msg) } (ty::UniqueImmBorrow, _) => { - span_err!(self.bccx, new_loan.span, E0500, - "closure requires unique access to `{}` \ - but {} is already borrowed{}", - nl, ol_pronoun, old_loan_msg); + struct_span_err!(self.bccx, new_loan.span, E0500, + "closure requires unique access to `{}` \ + but {} is already borrowed{}", + nl, ol_pronoun, old_loan_msg) } (_, ty::UniqueImmBorrow) => { - span_err!(self.bccx, new_loan.span, E0501, - "cannot borrow `{}`{} as {} because \ - previous closure requires unique access", - nl, new_loan_msg, new_loan.kind.to_user_str()); + struct_span_err!(self.bccx, new_loan.span, E0501, + "cannot borrow `{}`{} as {} because \ + previous closure requires unique access", + nl, new_loan_msg, new_loan.kind.to_user_str()) } (_, _) => { - span_err!(self.bccx, new_loan.span, E0502, - "cannot borrow `{}`{} as {} because \ - {} is also borrowed as {}{}", - nl, - new_loan_msg, - new_loan.kind.to_user_str(), - ol_pronoun, - old_loan.kind.to_user_str(), - old_loan_msg); + struct_span_err!(self.bccx, new_loan.span, E0502, + "cannot borrow `{}`{} as {} because \ + {} is also borrowed as {}{}", + nl, + new_loan_msg, + new_loan.kind.to_user_str(), + ol_pronoun, + old_loan.kind.to_user_str(), + old_loan_msg) } - } + }; match new_loan.cause { euv::ClosureCapture(span) => { - self.bccx.span_note( + err.span_note( span, &format!("borrow occurs due to use of `{}` in closure", nl)); @@ -553,15 +553,15 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { } }; - self.bccx.span_note( + err.span_note( old_loan.span, &format!("{}; {}", borrow_summary, rule_summary)); let old_loan_span = self.tcx().map.span( old_loan.kill_scope.node_id(&self.tcx().region_maps)); - self.bccx.span_end_note(old_loan_span, - "previous borrow ends here"); - + err.span_end_note(old_loan_span, + "previous borrow ends here"); + err.emit(); return false; } @@ -616,14 +616,14 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { match self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow) { UseOk => { } UseWhileBorrowed(loan_path, loan_span) => { - span_err!(self.bccx, span, E0503, - "cannot use `{}` because it was mutably borrowed", - &self.bccx.loan_path_to_string(copy_path)); - self.bccx.span_note( - loan_span, - &format!("borrow of `{}` occurs here", - &self.bccx.loan_path_to_string(&*loan_path)) - ); + struct_span_err!(self.bccx, span, E0503, + "cannot use `{}` because it was mutably borrowed", + &self.bccx.loan_path_to_string(copy_path)) + .span_note(loan_span, + &format!("borrow of `{}` occurs here", + &self.bccx.loan_path_to_string(&*loan_path)) + ) + .emit(); } } } @@ -639,24 +639,25 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { match self.analyze_restrictions_on_use(id, move_path, ty::MutBorrow) { UseOk => { } UseWhileBorrowed(loan_path, loan_span) => { - match move_kind { + let mut err = match move_kind { move_data::Captured => - span_err!(self.bccx, span, E0504, - "cannot move `{}` into closure because it is borrowed", - &self.bccx.loan_path_to_string(move_path)), + struct_span_err!(self.bccx, span, E0504, + "cannot move `{}` into closure because it is borrowed", + &self.bccx.loan_path_to_string(move_path)), move_data::Declared | move_data::MoveExpr | move_data::MovePat => - span_err!(self.bccx, span, E0505, - "cannot move out of `{}` because it is borrowed", - &self.bccx.loan_path_to_string(move_path)) + struct_span_err!(self.bccx, span, E0505, + "cannot move out of `{}` because it is borrowed", + &self.bccx.loan_path_to_string(move_path)) }; - self.bccx.span_note( + err.span_note( loan_span, &format!("borrow of `{}` occurs here", &self.bccx.loan_path_to_string(&*loan_path)) ); + err.emit(); } } } @@ -818,12 +819,12 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { span: Span, loan_path: &LoanPath<'tcx>, loan: &Loan) { - span_err!(self.bccx, span, E0506, - "cannot assign to `{}` because it is borrowed", - self.bccx.loan_path_to_string(loan_path)); - self.bccx.span_note( - loan.span, - &format!("borrow of `{}` occurs here", - self.bccx.loan_path_to_string(loan_path))); + struct_span_err!(self.bccx, span, E0506, + "cannot assign to `{}` because it is borrowed", + self.bccx.loan_path_to_string(loan_path)) + .span_note(loan.span, + &format!("borrow of `{}` occurs here", + self.bccx.loan_path_to_string(loan_path))) + .emit(); } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index a56a03174f609..4cb9673785ecb 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -15,6 +15,7 @@ use rustc::middle::mem_categorization::InteriorOffsetKind as Kind; use rustc::middle::ty; use syntax::ast; use syntax::codemap; +use syntax::errors::DiagnosticBuilder; use rustc_front::hir; pub struct MoveErrorCollector<'tcx> { @@ -68,13 +69,14 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &Vec>) { let grouped_errors = group_errors_with_same_origin(errors); for error in &grouped_errors { - report_cannot_move_out_of(bccx, error.move_from.clone()); + let mut err = report_cannot_move_out_of(bccx, error.move_from.clone()); let mut is_first_note = true; for move_to in &error.move_to_places { - note_move_destination(bccx, move_to.span, + note_move_destination(&mut err, move_to.span, move_to.name, is_first_note); is_first_note = false; } + err.emit(); } } @@ -112,24 +114,28 @@ fn group_errors_with_same_origin<'tcx>(errors: &Vec>) // (keep in sync with gather_moves::check_and_get_illegal_move_origin ) fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - move_from: mc::cmt<'tcx>) { + move_from: mc::cmt<'tcx>) + -> DiagnosticBuilder<'a> { match move_from.cat { Categorization::Deref(_, _, mc::BorrowedPtr(..)) | Categorization::Deref(_, _, mc::Implicit(..)) | Categorization::Deref(_, _, mc::UnsafePtr(..)) | Categorization::StaticItem => { - span_err!(bccx, move_from.span, E0507, - "cannot move out of {}", - move_from.descriptive_string(bccx.tcx)); + struct_span_err!(bccx, move_from.span, E0507, + "cannot move out of {}", + move_from.descriptive_string(bccx.tcx)) } Categorization::Interior(ref b, mc::InteriorElement(Kind::Index, _)) => { let expr = bccx.tcx.map.expect_expr(move_from.id); if let hir::ExprIndex(..) = expr.node { - span_err!(bccx, move_from.span, E0508, - "cannot move out of type `{}`, \ - a non-copy fixed-size array", - b.ty); + struct_span_err!(bccx, move_from.span, E0508, + "cannot move out of type `{}`, \ + a non-copy fixed-size array", + b.ty) + } else { + bccx.span_bug(move_from.span, "this path should not cause illegal move"); + unreachable!(); } } @@ -138,39 +144,41 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, match b.ty.sty { ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { - span_err!(bccx, move_from.span, E0509, - "cannot move out of type `{}`, \ - which defines the `Drop` trait", - b.ty); + struct_span_err!(bccx, move_from.span, E0509, + "cannot move out of type `{}`, \ + which defines the `Drop` trait", + b.ty) }, _ => { - bccx.span_bug(move_from.span, "this path should not cause illegal move") + bccx.span_bug(move_from.span, "this path should not cause illegal move"); + unreachable!(); } } } _ => { - bccx.span_bug(move_from.span, "this path should not cause illegal move") + bccx.span_bug(move_from.span, "this path should not cause illegal move"); + unreachable!(); } } } -fn note_move_destination(bccx: &BorrowckCtxt, +fn note_move_destination(err: &mut DiagnosticBuilder, move_to_span: codemap::Span, pat_name: ast::Name, is_first_note: bool) { if is_first_note { - bccx.span_note( + err.span_note( move_to_span, "attempting to move value to here"); - bccx.fileline_help( + err.fileline_help( move_to_span, &format!("to prevent the move, \ - use `ref {0}` or `ref mut {0}` to capture value by \ - reference", - pat_name)); + use `ref {0}` or `ref mut {0}` to capture value by \ + reference", + pat_name)); } else { - bccx.span_note(move_to_span, - &format!("and here (use `ref {0}` or `ref mut {0}`)", + err.span_note(move_to_span, + &format!("and here (use `ref {0}` or `ref mut {0}`)", pat_name)); } } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 38ec728e9c16f..0a2586755cef4 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -40,6 +40,7 @@ use std::mem; use std::rc::Rc; use syntax::ast; use syntax::codemap::Span; +use syntax::errors::DiagnosticBuilder; use rustc_front::hir; use rustc_front::hir::{FnDecl, Block}; @@ -591,10 +592,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } // General fallback. - self.span_err( + let mut db = self.struct_span_err( err.span, &self.bckerr_to_string(&err)); - self.note_and_explain_bckerr(err); + self.note_and_explain_bckerr(&mut db, err); + db.emit(); } pub fn report_use_of_moved_value<'b>(&self, @@ -609,16 +611,17 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { MovedInCapture => "capture", }; - let (ol, moved_lp_msg) = match the_move.kind { + let (ol, moved_lp_msg, mut err) = match the_move.kind { move_data::Declared => { - span_err!( + let err = struct_span_err!( self.tcx.sess, use_span, E0381, "{} of possibly uninitialized variable: `{}`", verb, self.loan_path_to_string(lp)); (self.loan_path_to_string(moved_lp), - String::new()) + String::new(), + err) } _ => { // If moved_lp is something like `x.a`, and lp is something like `x.b`, we would @@ -653,11 +656,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { let msg = if !has_fork && partial { "partially " } else if has_fork && !has_common { "collaterally "} else { "" }; - span_err!( + let err = struct_span_err!( self.tcx.sess, use_span, E0382, "{} of {}moved value: `{}`", verb, msg, nl); - (ol, moved_lp_msg) + (ol, moved_lp_msg, err) } }; @@ -684,7 +687,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { // multiple times. Avoid printing the same span and adjust the wording so it makes // more sense that it's from multiple evalutations. if expr_span == use_span { - self.tcx.sess.note( + err.note( &format!("`{}` was previously moved here{} because it has type `{}`, \ which is {}", ol, @@ -692,7 +695,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { expr_ty, suggestion)); } else { - self.tcx.sess.span_note( + err.span_note( expr_span, &format!("`{}` moved here{} because it has type `{}`, which is {}", ol, @@ -705,7 +708,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { move_data::MovePat => { let pat_ty = self.tcx.node_id_to_type(the_move.id); let span = self.tcx.map.span(the_move.id); - self.tcx.sess.span_note(span, + err.span_note(span, &format!("`{}` moved here{} because it has type `{}`, \ which is moved by default", ol, @@ -713,14 +716,14 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { pat_ty)); match self.tcx.sess.codemap().span_to_snippet(span) { Ok(string) => { - self.tcx.sess.span_suggestion( + err.span_suggestion( span, &format!("if you would like to borrow the value instead, \ use a `ref` binding as shown:"), format!("ref {}", string)); }, Err(_) => { - self.tcx.sess.fileline_help(span, + err.fileline_help(span, "use `ref` to override"); }, } @@ -746,7 +749,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { expr_ty, ("moved by default", "make a copy and capture that instead to override")); - self.tcx.sess.span_note( + err.span_note( expr_span, &format!("`{}` moved into closure environment here{} because it \ has type `{}`, which is {}", @@ -754,9 +757,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { moved_lp_msg, moved_lp.ty, suggestion)); - self.tcx.sess.fileline_help(expr_span, help); + err.fileline_help(expr_span, help); } } + err.emit(); fn move_suggestion<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx>, span: Span, @@ -791,35 +795,36 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { lp: &LoanPath<'tcx>, assign: &move_data::Assignment) { - span_err!( + struct_span_err!( self.tcx.sess, span, E0384, "re-assignment of immutable variable `{}`", - self.loan_path_to_string(lp)); - self.tcx.sess.span_note(assign.span, "prior assignment occurs here"); + self.loan_path_to_string(lp)) + .span_note(assign.span, "prior assignment occurs here") + .emit(); } pub fn span_err(&self, s: Span, m: &str) { self.tcx.sess.span_err(s, m); } - pub fn span_err_with_code(&self, s: Span, msg: &str, code: &str) { - self.tcx.sess.span_err_with_code(s, msg, code); + pub fn struct_span_err(&self, s: Span, m: &str) -> DiagnosticBuilder<'a> { + self.tcx.sess.struct_span_err(s, m) } - pub fn span_bug(&self, s: Span, m: &str) { - self.tcx.sess.span_bug(s, m); - } - - pub fn span_note(&self, s: Span, m: &str) { - self.tcx.sess.span_note(s, m); + pub fn struct_span_err_with_code(&self, + s: Span, + msg: &str, + code: &str) + -> DiagnosticBuilder<'a> { + self.tcx.sess.struct_span_err_with_code(s, msg, code) } - pub fn span_end_note(&self, s: Span, m: &str) { - self.tcx.sess.span_end_note(s, m); + pub fn span_err_with_code(&self, s: Span, msg: &str, code: &str) { + self.tcx.sess.span_err_with_code(s, msg, code); } - pub fn fileline_help(&self, s: Span, m: &str) { - self.tcx.sess.fileline_help(s, m); + pub fn span_bug(&self, s: Span, m: &str) { + self.tcx.sess.span_bug(s, m); } pub fn bckerr_to_string(&self, err: &BckError<'tcx>) -> String { @@ -913,19 +918,19 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } }; - match cause { + let mut err = match cause { mc::AliasableOther => { - span_err!( + struct_span_err!( self.tcx.sess, span, E0385, - "{} in an aliasable location", prefix); + "{} in an aliasable location", prefix) } mc::AliasableReason::UnaliasableImmutable => { - span_err!( + struct_span_err!( self.tcx.sess, span, E0386, - "{} in an immutable container", prefix); + "{} in an immutable container", prefix) } mc::AliasableClosure(id) => { - span_err!( + let mut err = struct_span_err!( self.tcx.sess, span, E0387, "{} in a captured outer variable in an `Fn` closure", prefix); if let BorrowViolation(euv::ClosureCapture(_)) = kind { @@ -933,31 +938,32 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { // happen for nested closures, so we know the enclosing // closure incorrectly accepts an `Fn` while it needs to // be `FnMut`. - span_help!(self.tcx.sess, self.tcx.map.span(id), + span_help!(&mut err, self.tcx.map.span(id), "consider changing this to accept closures that implement `FnMut`"); } else { - span_help!(self.tcx.sess, self.tcx.map.span(id), + span_help!(&mut err, self.tcx.map.span(id), "consider changing this closure to take self by mutable reference"); } + err } mc::AliasableStatic | mc::AliasableStaticMut => { - span_err!( + struct_span_err!( self.tcx.sess, span, E0388, - "{} in a static location", prefix); + "{} in a static location", prefix) } mc::AliasableBorrowed => { - span_err!( + struct_span_err!( self.tcx.sess, span, E0389, - "{} in a `&` reference", prefix); + "{} in a `&` reference", prefix) } - } + }; if is_closure { - self.tcx.sess.fileline_help( - span, - "closures behind references must be called via `&mut`"); + err.fileline_help(span, + "closures behind references must be called via `&mut`"); } + err.emit(); } fn report_out_of_scope_escaping_closure_capture(&self, @@ -966,34 +972,30 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { { let cmt_path_or_string = self.cmt_to_path_or_string(&err.cmt); - span_err!( - self.tcx.sess, err.span, E0373, - "closure may outlive the current function, \ - but it borrows {}, \ - which is owned by the current function", - cmt_path_or_string); - - self.tcx.sess.span_note( - capture_span, - &format!("{} is borrowed here", - cmt_path_or_string)); - let suggestion = match self.tcx.sess.codemap().span_to_snippet(err.span) { Ok(string) => format!("move {}", string), Err(_) => format!("move || ") }; - self.tcx.sess.span_suggestion( - err.span, - &format!("to force the closure to take ownership of {} \ - (and any other referenced variables), \ - use the `move` keyword, as shown:", - cmt_path_or_string), - suggestion); + struct_span_err!(self.tcx.sess, err.span, E0373, + "closure may outlive the current function, \ + but it borrows {}, \ + which is owned by the current function", + cmt_path_or_string) + .span_note(capture_span, + &format!("{} is borrowed here", + cmt_path_or_string)) + .span_suggestion(err.span, + &format!("to force the closure to take ownership of {} \ + (and any other referenced variables), \ + use the `move` keyword, as shown:", + cmt_path_or_string), + suggestion) + .emit(); } - pub fn note_and_explain_bckerr(&self, err: BckError<'tcx>) { + pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) { let code = err.code; match code { err_mutbl => { @@ -1007,7 +1009,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { _ => unreachable!() }; if kind == ty::FnClosureKind { - self.tcx.sess.span_help( + db.span_help( self.tcx.map.span(upvar_id.closure_expr_id), "consider changing this closure to take \ self by mutable reference"); @@ -1017,7 +1019,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { if let Categorization::Local(local_id) = err.cmt.cat { let span = self.tcx.map.span(local_id); if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { - self.tcx.sess.span_suggestion( + db.span_suggestion( span, &format!("to make the {} mutable, use `mut` as shown:", self.cmt_to_string(&err.cmt)), @@ -1030,16 +1032,18 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { err_out_of_scope(super_scope, sub_scope) => { self.tcx.note_and_explain_region( + db, "reference must be valid for ", sub_scope, "..."); self.tcx.note_and_explain_region( + db, "...but borrowed value is only valid for ", super_scope, ""); if let Some(span) = statement_scope_span(self.tcx, super_scope) { - self.tcx.sess.span_help(span, - "consider using a `let` binding to increase its lifetime"); + db.span_help(span, + "consider using a `let` binding to increase its lifetime"); } } @@ -1051,11 +1055,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { None => self.cmt_to_string(&*err.cmt), }; self.tcx.note_and_explain_region( + db, &format!("{} would have to be valid for ", descr), loan_scope, "..."); self.tcx.note_and_explain_region( + db, &format!("...but {} is only valid for ", descr), ptr_scope, ""); diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 1ac1b5978cfb6..27740b8fc5cf9 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1001,8 +1001,9 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec { - session.span_err(a.span, "`crate_type` requires a value"); - session.note("for example: `#![crate_type=\"lib\"]`"); + session.struct_span_err(a.span, "`crate_type` requires a value") + .note("for example: `#![crate_type=\"lib\"]`") + .emit(); None } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f27cc629791ed..24b346b3b317f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -752,19 +752,20 @@ impl LateLintPass for UnconditionalRecursion { // no break */ }`) shouldn't be linted unless it actually // recurs. if !reached_exit_without_self_call && !self_call_spans.is_empty() { - cx.span_lint(UNCONDITIONAL_RECURSION, sp, - "function cannot return without recurring"); + let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION, sp, + "function cannot return without recurring"); + let mut db = db.as_mut(); // FIXME #19668: these could be span_lint_note's instead of this manual guard. if cx.current_level(UNCONDITIONAL_RECURSION) != Level::Allow { - let sess = cx.sess(); // offer some help to the programmer. for call in &self_call_spans { - sess.span_note(*call, "recursive call site") + db = db.map(|db| db.span_note(*call, "recursive call site")); } - sess.fileline_help(sp, "a `loop` may express intention \ - better if this is on purpose") + db = db.map(|db| db.fileline_help(sp, "a `loop` may express intention \ + better if this is on purpose")); } + db.map(|db| db.emit()); } // all done diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 4420da5f9b87d..9122148a8cc05 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -35,6 +35,7 @@ use syntax::codemap::{self, Span, mk_sp, Pos}; use syntax::parse; use syntax::attr; use syntax::attr::AttrMetaMethods; +use syntax::errors::FatalError; use syntax::parse::token::InternedString; use syntax::util::small_vector::SmallVector; use rustc_front::intravisit::Visitor; @@ -504,7 +505,10 @@ impl<'a> CrateReader<'a> { let lo = p.span.lo; let body = match p.parse_all_token_trees() { Ok(body) => body, - Err(err) => panic!(err), + Err(mut err) => { + err.emit(); + panic!(FatalError); + } }; let span = mk_sp(lo, p.last_span.hi); p.abort_if_errors(); diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index d1892b87f8bcc..b82b76a57c463 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -226,7 +226,7 @@ use rustc_llvm as llvm; use rustc_llvm::{False, ObjectFile, mk_section_iter}; use rustc_llvm::archive_ro::ArchiveRO; use syntax::codemap::Span; -use syntax::errors::Handler; +use syntax::errors::DiagnosticBuilder; use rustc_back::target::Target; use std::cmp; @@ -315,38 +315,38 @@ impl<'a> Context<'a> { &Some(ref r) => format!(" which `{}` depends on", r.ident) }; - if !self.rejected_via_hash.is_empty() { - span_err!(self.sess, self.span, E0460, - "found possibly newer version of crate `{}`{}", - self.ident, add); + let mut err = if !self.rejected_via_hash.is_empty() { + struct_span_err!(self.sess, self.span, E0460, + "found possibly newer version of crate `{}`{}", + self.ident, add) } else if !self.rejected_via_triple.is_empty() { - span_err!(self.sess, self.span, E0461, - "couldn't find crate `{}` with expected target triple {}{}", - self.ident, self.triple, add); + struct_span_err!(self.sess, self.span, E0461, + "couldn't find crate `{}` with expected target triple {}{}", + self.ident, self.triple, add) } else if !self.rejected_via_kind.is_empty() { - span_err!(self.sess, self.span, E0462, - "found staticlib `{}` instead of rlib or dylib{}", - self.ident, add); + struct_span_err!(self.sess, self.span, E0462, + "found staticlib `{}` instead of rlib or dylib{}", + self.ident, add) } else { - span_err!(self.sess, self.span, E0463, - "can't find crate for `{}`{}", - self.ident, add); - } + struct_span_err!(self.sess, self.span, E0463, + "can't find crate for `{}`{}", + self.ident, add) + }; if !self.rejected_via_triple.is_empty() { let mismatches = self.rejected_via_triple.iter(); for (i, &CrateMismatch{ ref path, ref got }) in mismatches.enumerate() { - self.sess.fileline_note(self.span, + err.fileline_note(self.span, &format!("crate `{}`, path #{}, triple {}: {}", self.ident, i+1, got, path.display())); } } if !self.rejected_via_hash.is_empty() { - self.sess.span_note(self.span, "perhaps this crate needs \ + err.span_note(self.span, "perhaps this crate needs \ to be recompiled?"); let mismatches = self.rejected_via_hash.iter(); for (i, &CrateMismatch{ ref path, .. }) in mismatches.enumerate() { - self.sess.fileline_note(self.span, + err.fileline_note(self.span, &format!("crate `{}` path #{}: {}", self.ident, i+1, path.display())); } @@ -354,7 +354,7 @@ impl<'a> Context<'a> { &None => {} &Some(ref r) => { for (i, path) in r.paths().iter().enumerate() { - self.sess.fileline_note(self.span, + err.fileline_note(self.span, &format!("crate `{}` path #{}: {}", r.ident, i+1, path.display())); } @@ -362,15 +362,17 @@ impl<'a> Context<'a> { } } if !self.rejected_via_kind.is_empty() { - self.sess.fileline_help(self.span, "please recompile this crate using \ - --crate-type lib"); + err.fileline_help(self.span, "please recompile this crate using \ + --crate-type lib"); let mismatches = self.rejected_via_kind.iter(); for (i, &CrateMismatch { ref path, .. }) in mismatches.enumerate() { - self.sess.fileline_note(self.span, - &format!("crate `{}` path #{}: {}", - self.ident, i+1, path.display())); + err.fileline_note(self.span, + &format!("crate `{}` path #{}: {}", + self.ident, i+1, path.display())); } } + + err.emit(); self.sess.abort_if_errors(); } @@ -480,29 +482,30 @@ impl<'a> Context<'a> { 0 => None, 1 => Some(libraries.into_iter().next().unwrap()), _ => { - span_err!(self.sess, self.span, E0464, - "multiple matching crates for `{}`", - self.crate_name); - self.sess.note("candidates:"); + let mut err = struct_span_err!(self.sess, self.span, E0464, + "multiple matching crates for `{}`", + self.crate_name); + err.note("candidates:"); for lib in &libraries { match lib.dylib { Some((ref p, _)) => { - self.sess.note(&format!("path: {}", - p.display())); + err.note(&format!("path: {}", + p.display())); } None => {} } match lib.rlib { Some((ref p, _)) => { - self.sess.note(&format!("path: {}", - p.display())); + err.note(&format!("path: {}", + p.display())); } None => {} } let data = lib.metadata.as_slice(); let name = decoder::get_crate_name(data); - note_crate_name(self.sess.diagnostic(), &name); + note_crate_name(&mut err, &name); } + err.emit(); None } } @@ -533,6 +536,7 @@ impl<'a> Context<'a> { } } + let mut err: Option = None; for (lib, kind) in m { info!("{} reading metadata from: {}", flavor, lib.display()); let metadata = match get_metadata_section(self.target, &lib) { @@ -555,27 +559,37 @@ impl<'a> Context<'a> { // candidates have the same hash, so they're not actually // duplicates that we should warn about. if ret.is_some() && self.hash.is_none() { - span_err!(self.sess, self.span, E0465, - "multiple {} candidates for `{}` found", - flavor, self.crate_name); - self.sess.span_note(self.span, - &format!(r"candidate #1: {}", - ret.as_ref().unwrap().0 - .display())); + let mut e = struct_span_err!(self.sess, self.span, E0465, + "multiple {} candidates for `{}` found", + flavor, self.crate_name); + e.span_note(self.span, + &format!(r"candidate #1: {}", + ret.as_ref().unwrap().0 + .display())); + if let Some(ref mut e) = err { + e.emit(); + } + err = Some(e); error = 1; ret = None; } if error > 0 { error += 1; - self.sess.span_note(self.span, - &format!(r"candidate #{}: {}", error, - lib.display())); + err.as_mut().unwrap().span_note(self.span, + &format!(r"candidate #{}: {}", error, + lib.display())); continue } *slot = Some(metadata); ret = Some((lib, kind)); } - return if error > 0 {None} else {ret} + + if error > 0 { + err.unwrap().emit(); + None + } else { + ret + } } fn crate_matches(&mut self, crate_data: &[u8], libpath: &Path) -> bool { @@ -699,8 +713,8 @@ impl<'a> Context<'a> { } } -pub fn note_crate_name(diag: &Handler, name: &str) { - diag.note(&format!("crate name: {}", name)); +pub fn note_crate_name(err: &mut DiagnosticBuilder, name: &str) { + err.note(&format!("crate name: {}", name)); } impl ArchiveMetadata { diff --git a/src/librustc_plugin/build.rs b/src/librustc_plugin/build.rs index 476425a75c22d..5adde4304f57c 100644 --- a/src/librustc_plugin/build.rs +++ b/src/librustc_plugin/build.rs @@ -46,10 +46,11 @@ pub fn find_plugin_registrar(diagnostic: &errors::Handler, Some(node_id) }, _ => { - diagnostic.err("multiple plugin registration functions found"); + let mut e = diagnostic.struct_err("multiple plugin registration functions found"); for &(_, span) in &finder.registrars { - diagnostic.span_note(span, "one is here"); + e.span_note(span, "one is here"); } + e.emit(); diagnostic.abort_if_errors(); unreachable!(); } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index d1a894c61f7e2..1cc2482a39e27 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -597,13 +597,11 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { match result { None => true, Some((span, msg, note)) => { - self.tcx.sess.span_err(span, &msg[..]); - match note { - Some((span, msg)) => { - self.tcx.sess.span_note(span, &msg[..]) - } - None => {}, + let mut err = self.tcx.sess.struct_span_err(span, &msg[..]); + if let Some((span, msg)) = note { + err.span_note(span, &msg[..]); } + err.emit(); false }, } @@ -1028,10 +1026,12 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { fn check_sane_privacy(&self, item: &hir::Item) { let check_inherited = |sp, vis, note: &str| { if vis != hir::Inherited { - span_err!(self.tcx.sess, sp, E0449, "unnecessary visibility qualifier"); + let mut err = struct_span_err!(self.tcx.sess, sp, E0449, + "unnecessary visibility qualifier"); if !note.is_empty() { - self.tcx.sess.span_note(sp, note); + err.span_note(sp, note); } + err.emit(); } }; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 11d09fa3e9a6b..91fed4e5b9cf3 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -24,7 +24,7 @@ use {names_to_string, module_to_string}; use ParentLink::{self, ModuleParentLink, BlockParentLink}; use Resolver; use resolve_imports::Shadowable; -use {resolve_error, ResolutionError}; +use {resolve_error, resolve_struct_error, ResolutionError}; use self::DuplicateCheckingMode::*; @@ -137,12 +137,16 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { // Record an error here by looking up the namespace that had the duplicate let ns_str = match ns { TypeNS => "type or module", ValueNS => "value" }; - resolve_error(self, sp, ResolutionError::DuplicateDefinition(ns_str, name)); + let mut err = resolve_struct_error(self, + sp, + ResolutionError::DuplicateDefinition(ns_str, + name)); if let Some(sp) = child[ns].span() { let note = format!("first definition of {} `{}` here", ns_str, name); - self.session.span_note(sp, ¬e); + err.as_mut().map(|mut e| e.span_note(sp, ¬e)); } + err.as_mut().map(|mut e| e.emit()); child } } @@ -253,13 +257,14 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { }) .collect::>(); if mod_spans.len() > 1 { - resolve_error(self, + let mut e = resolve_struct_error(self, mod_spans[0], ResolutionError::SelfImportCanOnlyAppearOnceInTheList); for other_span in mod_spans.iter().skip(1) { - self.session - .span_note(*other_span, "another `self` import appears here"); + e.as_mut().map(|mut e| e.span_note(*other_span, + "another `self` import appears here")); } + e.as_mut().map(|mut e| e.emit()); } for source_item in source_items { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 3647fd5ce190a..67895ed213174 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -63,8 +63,9 @@ use syntax::ast; use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, TyIs, TyI8, TyI16, TyI32, TyI64}; use syntax::ast::{TyUs, TyU8, TyU16, TyU32, TyU64, TyF64, TyF32}; use syntax::attr::AttrMetaMethods; -use syntax::parse::token::{self, special_names, special_idents}; use syntax::codemap::{self, Span, Pos}; +use syntax::errors::DiagnosticBuilder; +use syntax::parse::token::{self, special_names, special_idents}; use syntax::util::lev_distance::find_best_match_for_name; use rustc_front::intravisit::{self, FnKind, Visitor}; @@ -215,210 +216,221 @@ pub enum UnresolvedNameContext { fn resolve_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, span: syntax::codemap::Span, resolution_error: ResolutionError<'b>) { + resolve_struct_error(resolver, span, resolution_error).map(|mut e| e.emit()); +} + +fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, + span: syntax::codemap::Span, + resolution_error: ResolutionError<'b>) + -> Option> { if !resolver.emit_errors { - return; + return None; } - match resolution_error { + + Some(match resolution_error { ResolutionError::TypeParametersFromOuterFunction => { - span_err!(resolver.session, - span, - E0401, - "can't use type parameters from outer function; try using a local type \ - parameter instead"); + struct_span_err!(resolver.session, + span, + E0401, + "can't use type parameters from outer function; try using a local \ + type parameter instead") } ResolutionError::OuterTypeParameterContext => { - span_err!(resolver.session, - span, - E0402, - "cannot use an outer type parameter in this context"); + struct_span_err!(resolver.session, + span, + E0402, + "cannot use an outer type parameter in this context") } ResolutionError::NameAlreadyUsedInTypeParameterList(name) => { - span_err!(resolver.session, - span, - E0403, - "the name `{}` is already used for a type parameter in this type parameter \ - list", - name); + struct_span_err!(resolver.session, + span, + E0403, + "the name `{}` is already used for a type parameter in this type \ + parameter list", + name) } ResolutionError::IsNotATrait(name) => { - span_err!(resolver.session, span, E0404, "`{}` is not a trait", name); + struct_span_err!(resolver.session, span, E0404, "`{}` is not a trait", name) } ResolutionError::UndeclaredTraitName(name) => { - span_err!(resolver.session, - span, - E0405, - "use of undeclared trait name `{}`", - name); + struct_span_err!(resolver.session, + span, + E0405, + "use of undeclared trait name `{}`", + name) } ResolutionError::UndeclaredAssociatedType => { - span_err!(resolver.session, span, E0406, "undeclared associated type"); + struct_span_err!(resolver.session, span, E0406, "undeclared associated type") } ResolutionError::MethodNotMemberOfTrait(method, trait_) => { - span_err!(resolver.session, - span, - E0407, - "method `{}` is not a member of trait `{}`", - method, - trait_); + struct_span_err!(resolver.session, + span, + E0407, + "method `{}` is not a member of trait `{}`", + method, + trait_) } ResolutionError::TypeNotMemberOfTrait(type_, trait_) => { - span_err!(resolver.session, - span, - E0437, - "type `{}` is not a member of trait `{}`", - type_, - trait_); + struct_span_err!(resolver.session, + span, + E0437, + "type `{}` is not a member of trait `{}`", + type_, + trait_) } ResolutionError::ConstNotMemberOfTrait(const_, trait_) => { - span_err!(resolver.session, - span, - E0438, - "const `{}` is not a member of trait `{}`", - const_, - trait_); + struct_span_err!(resolver.session, + span, + E0438, + "const `{}` is not a member of trait `{}`", + const_, + trait_) } ResolutionError::VariableNotBoundInPattern(variable_name, pattern_number) => { - span_err!(resolver.session, - span, - E0408, - "variable `{}` from pattern #1 is not bound in pattern #{}", - variable_name, - pattern_number); + struct_span_err!(resolver.session, + span, + E0408, + "variable `{}` from pattern #1 is not bound in pattern #{}", + variable_name, + pattern_number) } ResolutionError::VariableBoundWithDifferentMode(variable_name, pattern_number) => { - span_err!(resolver.session, - span, - E0409, - "variable `{}` is bound with different mode in pattern #{} than in pattern \ - #1", - variable_name, - pattern_number); + struct_span_err!(resolver.session, + span, + E0409, + "variable `{}` is bound with different mode in pattern #{} than in \ + pattern #1", + variable_name, + pattern_number) } ResolutionError::VariableNotBoundInParentPattern(variable_name, pattern_number) => { - span_err!(resolver.session, - span, - E0410, - "variable `{}` from pattern #{} is not bound in pattern #1", - variable_name, - pattern_number); + struct_span_err!(resolver.session, + span, + E0410, + "variable `{}` from pattern #{} is not bound in pattern #1", + variable_name, + pattern_number) } ResolutionError::SelfUsedOutsideImplOrTrait => { - span_err!(resolver.session, - span, - E0411, - "use of `Self` outside of an impl or trait"); + struct_span_err!(resolver.session, + span, + E0411, + "use of `Self` outside of an impl or trait") } ResolutionError::UseOfUndeclared(kind, name) => { - span_err!(resolver.session, - span, - E0412, - "use of undeclared {} `{}`", - kind, - name); + struct_span_err!(resolver.session, + span, + E0412, + "use of undeclared {} `{}`", + kind, + name) } ResolutionError::DeclarationShadowsEnumVariantOrUnitLikeStruct(name) => { - span_err!(resolver.session, - span, - E0413, - "declaration of `{}` shadows an enum variant or unit-like struct in scope", - name); + struct_span_err!(resolver.session, + span, + E0413, + "declaration of `{}` shadows an enum variant \ + or unit-like struct in scope", + name) } ResolutionError::OnlyIrrefutablePatternsAllowedHere(did, name) => { - span_err!(resolver.session, - span, - E0414, - "only irrefutable patterns allowed here"); - resolver.session.span_note(span, - "there already is a constant in scope sharing the same \ - name as this pattern"); + let mut err = struct_span_err!(resolver.session, + span, + E0414, + "only irrefutable patterns allowed here"); + err.span_note(span, + "there already is a constant in scope sharing the same \ + name as this pattern"); if let Some(sp) = resolver.ast_map.span_if_local(did) { - resolver.session.span_note(sp, "constant defined here"); + err.span_note(sp, "constant defined here"); } if let Some(directive) = resolver.current_module .import_resolutions .borrow() .get(&name) { let item = resolver.ast_map.expect_item(directive.value_ns.id); - resolver.session.span_note(item.span, "constant imported here"); + err.span_note(item.span, "constant imported here"); } + err } ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => { - span_err!(resolver.session, - span, - E0415, - "identifier `{}` is bound more than once in this parameter list", - identifier); + struct_span_err!(resolver.session, + span, + E0415, + "identifier `{}` is bound more than once in this parameter list", + identifier) } ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => { - span_err!(resolver.session, - span, - E0416, - "identifier `{}` is bound more than once in the same pattern", - identifier); + struct_span_err!(resolver.session, + span, + E0416, + "identifier `{}` is bound more than once in the same pattern", + identifier) } ResolutionError::StaticVariableReference => { - span_err!(resolver.session, - span, - E0417, - "static variables cannot be referenced in a pattern, use a `const` instead"); + struct_span_err!(resolver.session, + span, + E0417, + "static variables cannot be referenced in a pattern, use a \ + `const` instead") } ResolutionError::NotAnEnumVariantStructOrConst(name) => { - span_err!(resolver.session, - span, - E0418, - "`{}` is not an enum variant, struct or const", - name); + struct_span_err!(resolver.session, + span, + E0418, + "`{}` is not an enum variant, struct or const", + name) } ResolutionError::UnresolvedEnumVariantStructOrConst(name) => { - span_err!(resolver.session, - span, - E0419, - "unresolved enum variant, struct or const `{}`", - name); + struct_span_err!(resolver.session, + span, + E0419, + "unresolved enum variant, struct or const `{}`", + name) } ResolutionError::NotAnAssociatedConst(name) => { - span_err!(resolver.session, - span, - E0420, - "`{}` is not an associated const", - name); + struct_span_err!(resolver.session, + span, + E0420, + "`{}` is not an associated const", + name) } ResolutionError::UnresolvedAssociatedConst(name) => { - span_err!(resolver.session, - span, - E0421, - "unresolved associated const `{}`", - name); + struct_span_err!(resolver.session, + span, + E0421, + "unresolved associated const `{}`", + name) } ResolutionError::DoesNotNameAStruct(name) => { - span_err!(resolver.session, - span, - E0422, - "`{}` does not name a structure", - name); + struct_span_err!(resolver.session, + span, + E0422, + "`{}` does not name a structure", + name) } ResolutionError::StructVariantUsedAsFunction(path_name) => { - span_err!(resolver.session, - span, - E0423, - "`{}` is the name of a struct or struct variant, but this expression uses \ - it like a function name", - path_name); + struct_span_err!(resolver.session, + span, + E0423, + "`{}` is the name of a struct or struct variant, but this expression \ + uses it like a function name", + path_name) } ResolutionError::SelfNotAvailableInStaticMethod => { - span_err!(resolver.session, - span, - E0424, - "`self` is not available in a static method. Maybe a `self` argument is \ - missing?"); + struct_span_err!(resolver.session, + span, + E0424, + "`self` is not available in a static method. Maybe a `self` \ + argument is missing?") } ResolutionError::UnresolvedName(path, msg, context) => { - span_err!(resolver.session, - span, - E0425, - "unresolved name `{}`{}", - path, - msg); + let err = struct_span_err!(resolver.session, + span, + E0425, + "unresolved name `{}`{}", + path, + msg); match context { UnresolvedNameContext::Other => {} // no help available @@ -448,77 +460,79 @@ fn resolve_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, } if !help_msg.is_empty() { - resolver.session.fileline_help(span, &help_msg); + err.fileline_help(span, &help_msg); } } } + err } ResolutionError::UndeclaredLabel(name) => { - span_err!(resolver.session, - span, - E0426, - "use of undeclared label `{}`", - name); + struct_span_err!(resolver.session, + span, + E0426, + "use of undeclared label `{}`", + name) } ResolutionError::CannotUseRefBindingModeWith(descr) => { - span_err!(resolver.session, - span, - E0427, - "cannot use `ref` binding mode with {}", - descr); + struct_span_err!(resolver.session, + span, + E0427, + "cannot use `ref` binding mode with {}", + descr) } ResolutionError::DuplicateDefinition(namespace, name) => { - span_err!(resolver.session, - span, - E0428, - "duplicate definition of {} `{}`", - namespace, - name); + struct_span_err!(resolver.session, + span, + E0428, + "duplicate definition of {} `{}`", + namespace, + name) } ResolutionError::SelfImportsOnlyAllowedWithin => { - span_err!(resolver.session, - span, - E0429, - "{}", - "`self` imports are only allowed within a { } list"); + struct_span_err!(resolver.session, + span, + E0429, + "{}", + "`self` imports are only allowed within a { } list") } ResolutionError::SelfImportCanOnlyAppearOnceInTheList => { - span_err!(resolver.session, - span, - E0430, - "`self` import can only appear once in the list"); + struct_span_err!(resolver.session, + span, + E0430, + "`self` import can only appear once in the list") } ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => { - span_err!(resolver.session, - span, - E0431, - "`self` import can only appear in an import list with a non-empty prefix"); + struct_span_err!(resolver.session, + span, + E0431, + "`self` import can only appear in an import list with a \ + non-empty prefix") } ResolutionError::UnresolvedImport(name) => { let msg = match name { Some((n, p)) => format!("unresolved import `{}`{}", n, p), None => "unresolved import".to_owned(), }; - span_err!(resolver.session, span, E0432, "{}", msg); + struct_span_err!(resolver.session, span, E0432, "{}", msg) } ResolutionError::FailedToResolve(msg) => { - span_err!(resolver.session, span, E0433, "failed to resolve. {}", msg); + struct_span_err!(resolver.session, span, E0433, "failed to resolve. {}", msg) } ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => { - span_err!(resolver.session, - span, - E0434, - "{}", - "can't capture dynamic environment in a fn item; use the || { ... } \ - closure form instead"); + struct_span_err!(resolver.session, + span, + E0434, + "{}", + "can't capture dynamic environment in a fn item; use the || { ... } \ + closure form instead") } ResolutionError::AttemptToUseNonConstantValueInConstant => { - span_err!(resolver.session, - span, - E0435, - "attempt to use a non-constant value in a constant"); + struct_span_err!(resolver.session, + span, + E0435, + "attempt to use a non-constant value in a constant") } - } + }) } #[derive(Copy, Clone)] @@ -2180,16 +2194,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { debug!("(resolving trait) found trait def: {:?}", path_res); Ok(path_res) } else { - resolve_error(self, - trait_path.span, - ResolutionError::IsNotATrait(&*path_names_to_string(trait_path, - path_depth))); + let mut err = + resolve_struct_error(self, + trait_path.span, + ResolutionError::IsNotATrait(&*path_names_to_string(trait_path, + path_depth))); // If it's a typedef, give a note if let DefTy(..) = path_res.base_def { - self.session - .span_note(trait_path.span, "`type` aliases cannot be used for traits"); + err.as_mut().map(|mut e| e.span_note(trait_path.span, + "`type` aliases cannot be used for traits")); } + err.as_mut().map(|mut e| e.emit()); Err(()) } } else { @@ -3470,17 +3486,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let DefVariant(_, _, true) = path_res.base_def { let path_name = path_names_to_string(path, 0); - resolve_error(self, - expr.span, - ResolutionError::StructVariantUsedAsFunction(&*path_name)); + let mut err = resolve_struct_error(self, + expr.span, + ResolutionError::StructVariantUsedAsFunction(&*path_name)); let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?", path_name); if self.emit_errors { - self.session.fileline_help(expr.span, &msg); + err.as_mut().map(|mut e| e.fileline_help(expr.span, &msg)); } else { - self.session.span_help(expr.span, &msg); + err.as_mut().map(|mut e| e.span_help(expr.span, &msg)); } + err.as_mut().map(|mut e| e.emit()); self.record_def(expr.id, err_path_resolution()); } else { // Write the result into the def map. @@ -3510,20 +3527,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.record_def(expr.id, err_path_resolution()); match type_res.map(|r| r.base_def) { Some(DefTy(struct_id, _)) if self.structs.contains_key(&struct_id) => { - resolve_error( - self, - expr.span, - ResolutionError::StructVariantUsedAsFunction( - &*path_name) - ); + let mut err = resolve_struct_error(self, + expr.span, + ResolutionError::StructVariantUsedAsFunction(&*path_name)); let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?", path_name); if self.emit_errors { - self.session.fileline_help(expr.span, &msg); + err.as_mut().map(|mut e| e.fileline_help(expr.span, &msg)); } else { - self.session.span_help(expr.span, &msg); + err.as_mut().map(|mut e| e.span_help(expr.span, &msg)); } + err.as_mut().map(|mut e| e.emit()); } _ => { // Keep reporting some errors even if they're ignored above. diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 8b35f4d68df3b..40bf55efde645 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -454,8 +454,9 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { let note_msg = format!("Consider marking `{}` as `pub` in the imported \ module", source); - span_err!(self.resolver.session, directive.span, E0364, "{}", &msg); - self.resolver.session.span_note(directive.span, ¬e_msg); + struct_span_err!(self.resolver.session, directive.span, E0364, "{}", &msg) + .span_note(directive.span, ¬e_msg) + .emit(); pub_err = true; } if directive.is_public && child_name_bindings.value_ns. @@ -479,8 +480,9 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { let msg = format!("`{}` is private, and cannot be reexported", source); let note_msg = format!("Consider declaring module `{}` as a `pub mod`", source); - span_err!(self.resolver.session, directive.span, E0365, "{}", &msg); - self.resolver.session.span_note(directive.span, ¬e_msg); + struct_span_err!(self.resolver.session, directive.span, E0365, "{}", &msg) + .span_note(directive.span, ¬e_msg) + .emit(); } if !pub_err && directive.is_public && child_name_bindings.type_ns. defined_with(DefModifiers::PRIVATE_VARIANT) { @@ -959,19 +961,20 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { } ValueNS => "value", }; - span_err!(self.resolver.session, - import_span, - E0252, - "a {} named `{}` has already been imported in this module", - ns_word, - name); let use_id = import_resolution[namespace].id; let item = self.resolver.ast_map.expect_item(use_id); - // item is syntax::ast::Item; - span_note!(self.resolver.session, + let mut err = struct_span_err!(self.resolver.session, + import_span, + E0252, + "a {} named `{}` has already been imported \ + in this module", + ns_word, + name); + span_note!(&mut err, item.span, "previous import of `{}` here", name); + err.emit(); } Some(_) | None => {} } @@ -1022,14 +1025,16 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { match import.value_ns.target { Some(ref target) if target.shadowable != Shadowable::Always => { if let Some(ref value) = *name_bindings.value_ns.borrow() { - span_err!(self.resolver.session, - import_span, - E0255, - "import `{}` conflicts with value in this module", - name); + let mut err = struct_span_err!(self.resolver.session, + import_span, + E0255, + "import `{}` conflicts with \ + value in this module", + name); if let Some(span) = value.span { - self.resolver.session.span_note(span, "conflicting value here"); + err.span_note(span, "conflicting value here"); } + err.emit(); } } Some(_) | None => {} @@ -1045,15 +1050,16 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { ("trait in this module", "note conflicting trait here"), _ => ("type in this module", "note conflicting type here"), }; - span_err!(self.resolver.session, - import_span, - E0256, - "import `{}` conflicts with {}", - name, - what); + let mut err = struct_span_err!(self.resolver.session, + import_span, + E0256, + "import `{}` conflicts with {}", + name, + what); if let Some(span) = ty.span { - self.resolver.session.span_note(span, note); + err.span_note(span, note); } + err.emit(); } } Some(_) | None => {} diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs index f5431554a7564..850608588234c 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_trans/back/archive.rs @@ -406,11 +406,12 @@ impl<'a> ArchiveBuilder<'a> { Ok(prog) => { let o = prog.wait_with_output().unwrap(); if !o.status.success() { - sess.err(&format!("{:?} failed with: {}", cmd, o.status)); - sess.note(&format!("stdout ---\n{}", - str::from_utf8(&o.stdout).unwrap())); - sess.note(&format!("stderr ---\n{}", - str::from_utf8(&o.stderr).unwrap())); + sess.struct_err(&format!("{:?} failed with: {}", cmd, o.status)) + .note(&format!("stdout ---\n{}", + str::from_utf8(&o.stdout).unwrap())) + .note(&format!("stderr ---\n{}", + str::from_utf8(&o.stderr).unwrap())) + .emit(); sess.abort_if_errors(); } o diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index fb79f804932f8..cc7c218b07b2c 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -817,10 +817,10 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path, ab.build(); if !all_native_libs.is_empty() { - sess.note("link against the following native artifacts when linking against \ - this static library"); - sess.note("the order and any duplication can be significant on some platforms, \ - and so may need to be preserved"); + sess.note_without_error("link against the following native artifacts when linking against \ + this static library"); + sess.note_without_error("the order and any duplication can be significant on some \ + platforms, and so may need to be preserved"); } for &(kind, ref lib) in &all_native_libs { @@ -829,7 +829,7 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path, NativeLibraryKind::NativeUnknown => "library", NativeLibraryKind::NativeFramework => "framework", }; - sess.note(&format!("{}: {}", name, *lib)); + sess.note_without_error(&format!("{}: {}", name, *lib)); } } @@ -902,13 +902,14 @@ fn link_natively(sess: &Session, dylib: bool, }) } if !prog.status.success() { - sess.err(&format!("linking with `{}` failed: {}", - pname, - prog.status)); - sess.note(&format!("{:?}", &cmd)); let mut output = prog.stderr.clone(); output.extend_from_slice(&prog.stdout); - sess.note(&*escape_string(&output[..])); + sess.struct_err(&format!("linking with `{}` failed: {}", + pname, + prog.status)) + .note(&format!("{:?}", &cmd)) + .note(&*escape_string(&output[..])) + .emit(); sess.abort_if_errors(); } info!("linker stderr:\n{}", escape_string(&prog.stderr[..])); diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 8505c3968ee15..85419a072503a 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -29,8 +29,9 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, name_extra: &str, output_names: &config::OutputFilenames) { if sess.opts.cg.prefer_dynamic { - sess.err("cannot prefer dynamic linking when performing LTO"); - sess.note("only 'staticlib' and 'bin' outputs are supported with LTO"); + sess.struct_err("cannot prefer dynamic linking when performing LTO") + .note("only 'staticlib' and 'bin' outputs are supported with LTO") + .emit(); sess.abort_if_errors(); } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 67eff1ca19fbc..9d0a83fe36350 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -359,8 +359,9 @@ unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext<'a>, } None => { - cgcx.handler.err(msg); - cgcx.handler.note("build without -C codegen-units for more exact errors"); + cgcx.handler.struct_err(msg) + .note("build without -C codegen-units for more exact errors") + .emit(); } } } @@ -397,11 +398,11 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo if enabled { let loc = llvm::debug_loc_to_string(llcx, opt.debug_loc); - cgcx.handler.note(&format!("optimization {} for {} at {}: {}", - opt.kind.describe(), - pass_name, - if loc.is_empty() { "[unknown]" } else { &*loc }, - llvm::twine_to_string(opt.message))); + cgcx.handler.note_without_error(&format!("optimization {} for {} at {}: {}", + opt.kind.describe(), + pass_name, + if loc.is_empty() { "[unknown]" } else { &*loc }, + llvm::twine_to_string(opt.message))); } } @@ -931,13 +932,15 @@ pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) { match cmd.output() { Ok(prog) => { if !prog.status.success() { - sess.err(&format!("linking with `{}` failed: {}", - pname, - prog.status)); - sess.note(&format!("{:?}", &cmd)); let mut note = prog.stderr.clone(); note.extend_from_slice(&prog.stdout); - sess.note(str::from_utf8(¬e[..]).unwrap()); + + sess.struct_err(&format!("linking with `{}` failed: {}", + pname, + prog.status)) + .note(&format!("{:?}", &cmd)) + .note(str::from_utf8(¬e[..]).unwrap()) + .emit(); sess.abort_if_errors(); } }, diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 838a5435d4fee..d7fbe1193b6ba 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2181,17 +2181,20 @@ fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &hir::EnumDef, sp: Span, } ); + // FIXME(#30505) Should use logging for this. if print_info { let llty = type_of::sizing_type_of(ccx, ty); let sess = &ccx.tcx().sess; - sess.span_note(sp, &*format!("total size: {} bytes", llsize_of_real(ccx, llty))); + sess.span_note_without_error(sp, + &*format!("total size: {} bytes", llsize_of_real(ccx, llty))); match *avar { adt::General(..) => { for (i, var) in enum_def.variants.iter().enumerate() { ccx.tcx() .sess - .span_note(var.span, &*format!("variant data: {} bytes", sizes[i])); + .span_note_without_error(var.span, + &*format!("variant data: {} bytes", sizes[i])); } } _ => {} @@ -2203,16 +2206,18 @@ fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &hir::EnumDef, sp: Span, if !is_allow && largest > slargest * 3 && slargest > 0 { // Use lint::raw_emit_lint rather than sess.add_lint because the lint-printing // pass for the latter already ran. - lint::raw_emit_lint(&ccx.tcx().sess, - lint::builtin::VARIANT_SIZE_DIFFERENCES, - *lvlsrc.unwrap(), - Some(sp), - &format!("enum variant is more than three times larger ({} bytes) \ - than the next largest (ignoring padding)", - largest)); - - ccx.sess().span_note(enum_def.variants[largest_index].span, - "this variant is the largest"); + lint::raw_struct_lint(&ccx.tcx().sess, + lint::builtin::VARIANT_SIZE_DIFFERENCES, + *lvlsrc.unwrap(), + Some(sp), + &format!("enum variant is more than three times larger ({} bytes) \ + than the next largest (ignoring padding)", + largest)) + .map(|mut e| { + e.span_note(enum_def.variants[largest_index].span, + "this variant is the largest") + .emit(); + }); } } @@ -2489,9 +2494,10 @@ pub fn create_entry_wrapper(ccx: &CrateContext, sp: Span, main_llfn: ValueRef) { let llfty = Type::func(&[ccx.int_type(), Type::i8p(ccx).ptr_to()], &ccx.int_type()); let llfn = declare::define_cfn(ccx, "main", llfty, ccx.tcx().mk_nil()).unwrap_or_else(|| { - ccx.sess().span_err(sp, "entry symbol `main` defined multiple times"); // FIXME: We should be smart and show a better diagnostic here. - ccx.sess().help("did you use #[no_mangle] on `fn main`? Use #[start] instead"); + ccx.sess().struct_span_err(sp, "entry symbol `main` defined multiple times") + .help("did you use #[no_mangle] on `fn main`? Use #[start] instead") + .emit(); ccx.sess().abort_if_errors(); panic!(); }); diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 9012ecaa2134f..e6ad5ac4f063a 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -460,12 +460,13 @@ fn gate_simd_ffi(tcx: &ty::ctxt, decl: &hir::FnDecl, ty: &ty::BareFnTy) { if !tcx.sess.features.borrow().simd_ffi { let check = |ast_ty: &hir::Ty, ty: ty::Ty| { if ty.is_simd() { - tcx.sess.span_err(ast_ty.span, + tcx.sess.struct_span_err(ast_ty.span, &format!("use of SIMD type `{}` in FFI is highly experimental and \ may result in invalid code", - pprust::ty_to_string(ast_ty))); - tcx.sess.fileline_help(ast_ty.span, - "add #![feature(simd_ffi)] to the crate attributes to enable"); + pprust::ty_to_string(ast_ty))) + .fileline_help(ast_ty.span, + "add #![feature(simd_ffi)] to the crate attributes to enable") + .emit(); } }; let sig = &ty.sig.0; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 95d85964044da..751c18dfbc43d 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -68,6 +68,7 @@ use util::nodemap::FnvHashSet; use syntax::{abi, ast}; use syntax::codemap::{Span, Pos}; +use syntax::errors::DiagnosticBuilder; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::parse::token; @@ -195,7 +196,7 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &hir::Lifetime) } fn report_elision_failure( - tcx: &ty::ctxt, + db: &mut DiagnosticBuilder, default_span: Span, params: Vec) { @@ -233,26 +234,26 @@ fn report_elision_failure( } if len == 0 { - fileline_help!(tcx.sess, default_span, + fileline_help!(db, default_span, "this function's return type contains a borrowed value, but \ there is no value for it to be borrowed from"); - fileline_help!(tcx.sess, default_span, + fileline_help!(db, default_span, "consider giving it a 'static lifetime"); } else if !any_lifetimes { - fileline_help!(tcx.sess, default_span, + fileline_help!(db, default_span, "this function's return type contains a borrowed value with \ an elided lifetime, but the lifetime cannot be derived from \ the arguments"); - fileline_help!(tcx.sess, default_span, + fileline_help!(db, default_span, "consider giving it an explicit bounded or 'static \ lifetime"); } else if len == 1 { - fileline_help!(tcx.sess, default_span, + fileline_help!(db, default_span, "this function's return type contains a borrowed value, but \ the signature does not say which {} it is borrowed from", m); } else { - fileline_help!(tcx.sess, default_span, + fileline_help!(db, default_span, "this function's return type contains a borrowed value, but \ the signature does not say whether it is borrowed from {}", m); @@ -273,11 +274,12 @@ pub fn opt_ast_region_to_region<'tcx>( None => match rscope.anon_regions(default_span, 1) { Ok(rs) => rs[0], Err(params) => { - span_err!(this.tcx().sess, default_span, E0106, - "missing lifetime specifier"); + let mut err = struct_span_err!(this.tcx().sess, default_span, E0106, + "missing lifetime specifier"); if let Some(params) = params { - report_elision_failure(this.tcx(), default_span, params); + report_elision_failure(&mut err, default_span, params); } + err.emit(); ty::ReStatic } } @@ -1044,9 +1046,9 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>, } } _ => { - span_err!(this.tcx().sess, ty.span, E0178, - "expected a path on the left-hand side of `+`, not `{}`", - pprust::ty_to_string(ty)); + let mut err = struct_span_err!(this.tcx().sess, ty.span, E0178, + "expected a path on the left-hand side of `+`, not `{}`", + pprust::ty_to_string(ty)); let hi = bounds.iter().map(|x| match *x { hir::TraitTyParamBound(ref tr, _) => tr.span.hi, hir::RegionTyParamBound(ref r) => r.span.hi, @@ -1059,29 +1061,28 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>, match (&ty.node, full_span) { (&hir::TyRptr(None, ref mut_ty), Some(full_span)) => { let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" }; - this.tcx().sess - .span_suggestion(full_span, "try adding parentheses (per RFC 438):", - format!("&{}({} +{})", - mutbl_str, - pprust::ty_to_string(&*mut_ty.ty), - pprust::bounds_to_string(bounds))); + err.span_suggestion(full_span, "try adding parentheses (per RFC 438):", + format!("&{}({} +{})", + mutbl_str, + pprust::ty_to_string(&*mut_ty.ty), + pprust::bounds_to_string(bounds))); } (&hir::TyRptr(Some(ref lt), ref mut_ty), Some(full_span)) => { let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" }; - this.tcx().sess - .span_suggestion(full_span, "try adding parentheses (per RFC 438):", - format!("&{} {}({} +{})", - pprust::lifetime_to_string(lt), - mutbl_str, - pprust::ty_to_string(&*mut_ty.ty), - pprust::bounds_to_string(bounds))); + err.span_suggestion(full_span, "try adding parentheses (per RFC 438):", + format!("&{} {}({} +{})", + pprust::lifetime_to_string(lt), + mutbl_str, + pprust::ty_to_string(&*mut_ty.ty), + pprust::bounds_to_string(bounds))); } _ => { - fileline_help!(this.tcx().sess, ty.span, + fileline_help!(&mut err, ty.span, "perhaps you forgot parentheses? (per RFC 438)"); } } + err.emit(); Err(ErrorReported) } } @@ -1134,7 +1135,8 @@ fn make_object_type<'tcx>(this: &AstConv<'tcx>, traits::astconv_object_safety_violations(tcx, principal.def_id()); if !object_safety_violations.is_empty() { traits::report_object_safety_error( - tcx, span, principal.def_id(), object_safety_violations); + tcx, span, principal.def_id(), object_safety_violations) + .emit(); return tcx.types.err; } @@ -1235,17 +1237,18 @@ fn one_bound_for_assoc_type<'tcx>(tcx: &ty::ctxt<'tcx>, } if bounds.len() > 1 { - span_err!(tcx.sess, span, E0221, - "ambiguous associated type `{}` in bounds of `{}`", - assoc_name, - ty_param_name); + let mut err = struct_span_err!(tcx.sess, span, E0221, + "ambiguous associated type `{}` in bounds of `{}`", + assoc_name, + ty_param_name); for bound in &bounds { - span_note!(tcx.sess, span, + span_note!(&mut err, span, "associated type `{}` could derive from `{}`", ty_param_name, bound); } + err.emit(); } Ok(bounds[0].clone()) @@ -1707,12 +1710,13 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, } } Err(ref r) => { - span_err!(tcx.sess, r.span, E0250, - "array length constant evaluation error: {}", - r.description()); + let mut err = struct_span_err!(tcx.sess, r.span, E0250, + "array length constant evaluation error: {}", + r.description()); if !ast_ty.span.contains(r.span) { - span_note!(tcx.sess, ast_ty.span, "for array length here") + span_note!(&mut err, ast_ty.span, "for array length here") } + err.emit(); this.tcx().types.err } } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index efcc08c69f824..588dee57c520e 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -700,7 +700,9 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, if !is_special_case { return } else { - span_note!(tcx.sess, pat.span, + // Boo! Too painful to attach this to the actual warning, + // it should go away at some point though. + tcx.sess.span_note_without_error(pat.span, "this warning will become a HARD ERROR in a future release. \ See RFC 218 for details."); } @@ -786,12 +788,13 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, for &Spanned { node: ref field, span } in fields { let field_ty = match used_fields.entry(field.name) { Occupied(occupied) => { - span_err!(tcx.sess, span, E0025, - "field `{}` bound multiple times in the pattern", - field.name); - span_note!(tcx.sess, *occupied.get(), - "field `{}` previously bound here", - field.name); + let mut err = struct_span_err!(tcx.sess, span, E0025, + "field `{}` bound multiple times in the pattern", + field.name); + span_note!(&mut err, *occupied.get(), + "field `{}` previously bound here", + field.name); + err.emit(); tcx.types.err } Vacant(vacant) => { diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 1e20cd3985467..07a1da9206750 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -61,11 +61,12 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: return // not a closure method, everything is OK. }; - span_err!(tcx.sess, span, E0174, - "explicit use of unboxed closure method `{}` is experimental", - method); - fileline_help!(tcx.sess, span, - "add `#![feature(unboxed_closures)]` to the crate attributes to enable"); + struct_span_err!(tcx.sess, span, E0174, + "explicit use of unboxed closure method `{}` is experimental", + method) + .fileline_help(span, "add `#![feature(unboxed_closures)]` to the crate \ + attributes to enable") + .emit(); } } @@ -228,21 +229,24 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, sig } _ => { - fcx.type_error_message(call_expr.span, |actual| { + let mut err = fcx.type_error_struct(call_expr.span, |actual| { format!("expected function, found `{}`", actual) }, callee_ty, None); + let mut err = err.as_mut(); if let hir::ExprCall(ref expr, _) = call_expr.node { let tcx = fcx.tcx(); if let Some(pr) = tcx.def_map.borrow().get(&expr.id) { if pr.depth == 0 && pr.base_def != def::DefErr { if let Some(span) = tcx.map.span_if_local(pr.def_id()) { - tcx.sess.span_note(span, "defined here") + err = err.map(|e| e.span_note(span, "defined here")); } } } } + err.map(|e| e.emit()); + // This is the "default" function signature, used in case of error. // In that case, we check each argument against "error" in order to // set up all the node type bindings. diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 13e5e46ed2700..057671cad5cf4 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -127,23 +127,27 @@ impl<'tcx> CastCheck<'tcx> { CastError::NeedViaThinPtr | CastError::NeedViaInt | CastError::NeedViaUsize => { - fcx.type_error_message(self.span, |actual| { + fcx.type_error_struct(self.span, |actual| { format!("casting `{}` as `{}` is invalid", actual, fcx.infcx().ty_to_string(self.cast_ty)) - }, self.expr_ty, None); - fcx.ccx.tcx.sess.fileline_help(self.span, - &format!("cast through {} first", match e { - CastError::NeedViaPtr => "a raw pointer", - CastError::NeedViaThinPtr => "a thin pointer", - CastError::NeedViaInt => "an integer", - CastError::NeedViaUsize => "a usize", - _ => unreachable!() - })); + }, self.expr_ty, None) + .map(|mut err| { + err.fileline_help(self.span, + &format!("cast through {} first", match e { + CastError::NeedViaPtr => "a raw pointer", + CastError::NeedViaThinPtr => "a thin pointer", + CastError::NeedViaInt => "an integer", + CastError::NeedViaUsize => "a usize", + _ => unreachable!() + })); + err.emit(); + }); } CastError::CastToBool => { - span_err!(fcx.tcx().sess, self.span, E0054, "cannot cast as `bool`"); - fcx.ccx.tcx.sess.fileline_help(self.span, "compare with zero instead"); + struct_span_err!(fcx.tcx().sess, self.span, E0054, "cannot cast as `bool`") + .fileline_help(self.span, "compare with zero instead") + .emit(); } CastError::CastToChar => { fcx.type_error_message(self.span, |actual| { @@ -165,12 +169,15 @@ impl<'tcx> CastCheck<'tcx> { }, self.expr_ty, None); } CastError::DifferingKinds => { - fcx.type_error_message(self.span, |actual| { + fcx.type_error_struct(self.span, |actual| { format!("casting `{}` as `{}` is invalid", actual, fcx.infcx().ty_to_string(self.cast_ty)) - }, self.expr_ty, None); - fcx.ccx.tcx.sess.fileline_note(self.span, "vtable kinds may not match"); + }, self.expr_ty, None) + .map(|mut err| { + err.fileline_note(self.span, "vtable kinds may not match"); + err.emit(); + }); } } } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 59025346ce3bd..0cf552b6efecb 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -95,12 +95,13 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( if let Err(_) = infer::mk_eqty(&infcx, true, infer::TypeOrigin::Misc(drop_impl_span), named_type, fresh_impl_self_ty) { - span_err!(tcx.sess, drop_impl_span, E0366, - "Implementations of Drop cannot be specialized"); let item_span = tcx.map.span(self_type_node_id); - tcx.sess.span_note(item_span, - "Use same sequence of generic type and region \ - parameters that is on the struct/enum definition"); + struct_span_err!(tcx.sess, drop_impl_span, E0366, + "Implementations of Drop cannot be specialized") + .span_note(item_span, + "Use same sequence of generic type and region \ + parameters that is on the struct/enum definition") + .emit(); return Err(()); } @@ -197,11 +198,12 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( if !assumptions_in_impl_context.contains(&predicate) { let item_span = tcx.map.span(self_type_node_id); - span_err!(tcx.sess, drop_impl_span, E0367, - "The requirement `{}` is added only by the Drop impl.", predicate); - tcx.sess.span_note(item_span, - "The same requirement must be part of \ - the struct/enum definition"); + struct_span_err!(tcx.sess, drop_impl_span, E0367, + "The requirement `{}` is added only by the Drop impl.", predicate) + .span_note(item_span, + "The same requirement must be part of \ + the struct/enum definition") + .emit(); } } @@ -289,8 +291,8 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx> Ok(()) => {} Err(Error::Overflow(ref ctxt, ref detected_on_typ)) => { let tcx = rcx.tcx(); - span_err!(tcx.sess, span, E0320, - "overflow while adding drop-check rules for {}", typ); + let mut err = struct_span_err!(tcx.sess, span, E0320, + "overflow while adding drop-check rules for {}", typ); match *ctxt { TypeContext::Root => { // no need for an additional note if the overflow @@ -311,7 +313,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx> format!("`{}`", field) }; span_note!( - rcx.tcx().sess, + &mut err, span, "overflowed on {} field {} type: {}", variant_name, @@ -319,6 +321,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx> detected_on_typ); } } + err.emit(); } } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 955bc92a8f31e..5c0eefd5f85d4 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -27,6 +27,7 @@ use util::nodemap::{FnvHashSet}; use syntax::ast; use syntax::codemap::Span; +use syntax::errors::DiagnosticBuilder; use rustc_front::print::pprust; use rustc_front::hir; @@ -55,7 +56,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, mode }) => { let cx = fcx.tcx(); - fcx.type_error_message( + let mut err = fcx.type_error_struct( span, |actual| { format!("no {} named `{}` found for type `{}` \ @@ -68,100 +69,111 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, rcvr_ty, None); - // If the item has the name of a field, give a help note - if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { - if let Some(field) = def.struct_variant().find_field_named(item_name) { - let expr_string = match cx.sess.codemap().span_to_snippet(expr.span) { - Ok(expr_string) => expr_string, - _ => "s".into() // Default to a generic placeholder for the - // expression when we can't generate a string - // snippet - }; + if let Some(ref mut err) = err { + // If the item has the name of a field, give a help note + if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { + if let Some(field) = def.struct_variant().find_field_named(item_name) { + let expr_string = match cx.sess.codemap().span_to_snippet(expr.span) { + Ok(expr_string) => expr_string, + _ => "s".into() // Default to a generic placeholder for the + // expression when we can't generate a string + // snippet + }; + + macro_rules! span_stored_function { + () => { + err.span_note(span, + &format!("use `({0}.{1})(...)` if you meant to call \ + the function stored in the `{1}` field", + expr_string, item_name)); + } + } - let span_stored_function = || { - cx.sess.span_note(span, - &format!("use `({0}.{1})(...)` if you meant to call \ - the function stored in the `{1}` field", - expr_string, item_name)); - }; + macro_rules! span_did_you_mean { + () => { + err.span_note(span, &format!("did you mean to write `{0}.{1}`?", + expr_string, item_name)); + } + } - let span_did_you_mean = || { - cx.sess.span_note(span, &format!("did you mean to write `{0}.{1}`?", - expr_string, item_name)); - }; + // Determine if the field can be used as a function in some way + let field_ty = field.ty(cx, substs); - // Determine if the field can be used as a function in some way - let field_ty = field.ty(cx, substs); - - match field_ty.sty { - // Not all of these (e.g. unsafe fns) implement FnOnce - // so we look for these beforehand - ty::TyClosure(..) | ty::TyBareFn(..) => span_stored_function(), - // If it's not a simple function, look for things which implement FnOnce - _ => { - if let Ok(fn_once_trait_did) = - cx.lang_items.require(FnOnceTraitLangItem) { - let infcx = fcx.infcx(); - infcx.probe(|_| { - let fn_once_substs = Substs::new_trait(vec![ - infcx.next_ty_var()], - Vec::new(), - field_ty); - let trait_ref = ty::TraitRef::new(fn_once_trait_did, - cx.mk_substs(fn_once_substs)); - let poly_trait_ref = trait_ref.to_poly_trait_ref(); - let obligation = Obligation::misc(span, - fcx.body_id, - poly_trait_ref - .to_predicate()); - let mut selcx = SelectionContext::new(infcx); - - if selcx.evaluate_obligation(&obligation) { - span_stored_function(); - } else { - span_did_you_mean(); - } - }); - } else { - span_did_you_mean() + match field_ty.sty { + // Not all of these (e.g. unsafe fns) implement FnOnce + // so we look for these beforehand + ty::TyClosure(..) | ty::TyBareFn(..) => { + span_stored_function!(); + } + // If it's not a simple function, look for things which implement FnOnce + _ => { + if let Ok(fn_once_trait_did) = + cx.lang_items.require(FnOnceTraitLangItem) { + let infcx = fcx.infcx(); + infcx.probe(|_| { + let fn_once_substs = + Substs::new_trait(vec![infcx.next_ty_var()], + Vec::new(), + field_ty); + let trait_ref = + ty::TraitRef::new(fn_once_trait_did, + cx.mk_substs(fn_once_substs)); + let poly_trait_ref = trait_ref.to_poly_trait_ref(); + let obligation = Obligation::misc(span, + fcx.body_id, + poly_trait_ref + .to_predicate()); + let mut selcx = SelectionContext::new(infcx); + + if selcx.evaluate_obligation(&obligation) { + span_stored_function!(); + } else { + span_did_you_mean!(); + } + }); + } else { + span_did_you_mean!(); + } } } } } - } - if !static_sources.is_empty() { - cx.sess.fileline_note( - span, - "found defined static methods, maybe a `self` is missing?"); + if !static_sources.is_empty() { + err.fileline_note( + span, + "found defined static methods, maybe a `self` is missing?"); - report_candidates(fcx, span, item_name, static_sources); - } + report_candidates(fcx, err, span, item_name, static_sources); + } - if !unsatisfied_predicates.is_empty() { - let bound_list = unsatisfied_predicates.iter() - .map(|p| format!("`{} : {}`", - p.self_ty(), - p)) - .collect::>() - .join(", "); - cx.sess.fileline_note( - span, - &format!("the method `{}` exists but the \ - following trait bounds were not satisfied: {}", - item_name, - bound_list)); - } + if !unsatisfied_predicates.is_empty() { + let bound_list = unsatisfied_predicates.iter() + .map(|p| format!("`{} : {}`", + p.self_ty(), + p)) + .collect::>() + .join(", "); + err.fileline_note( + span, + &format!("the method `{}` exists but the \ + following trait bounds were not satisfied: {}", + item_name, + bound_list)); + } - suggest_traits_to_import(fcx, span, rcvr_ty, item_name, - rcvr_expr, out_of_scope_traits) + suggest_traits_to_import(fcx, err, span, rcvr_ty, item_name, + rcvr_expr, out_of_scope_traits); + err.emit(); + } } MethodError::Ambiguity(sources) => { - span_err!(fcx.sess(), span, E0034, - "multiple applicable items in scope"); + let mut err = struct_span_err!(fcx.sess(), span, E0034, + "multiple applicable items in scope"); - report_candidates(fcx, span, item_name, sources); + report_candidates(fcx, &mut err, span, item_name, sources); + err.emit(); } MethodError::ClosureAmbiguity(trait_def_id) => { @@ -181,6 +193,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } fn report_candidates(fcx: &FnCtxt, + err: &mut DiagnosticBuilder, span: Span, item_name: ast::Name, mut sources: Vec) { @@ -213,7 +226,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } }; - span_note!(fcx.sess(), item_span, + span_note!(err, item_span, "candidate #{} is defined in an impl{} for the type `{}`", idx + 1, insertion, @@ -222,7 +235,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, CandidateSource::TraitSource(trait_did) => { let item = trait_item(fcx.tcx(), trait_did, item_name).unwrap(); let item_span = fcx.tcx().map.def_id_span(item.def_id(), span); - span_note!(fcx.sess(), item_span, + span_note!(err, item_span, "candidate #{} is defined in the trait `{}`", idx + 1, fcx.tcx().item_path_str(trait_did)); @@ -236,6 +249,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, pub type AllTraitsVec = Vec; fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + err: &mut DiagnosticBuilder, span: Span, rcvr_ty: Ty<'tcx>, item_name: ast::Name, @@ -255,14 +269,13 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, traits_are = if candidates.len() == 1 {"trait is"} else {"traits are"}, one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}); - fcx.sess().fileline_help(span, &msg[..]); + err.fileline_help(span, &msg[..]); for (i, trait_did) in candidates.iter().enumerate() { - fcx.sess().fileline_help(span, - &*format!("candidate #{}: use `{}`", - i + 1, - fcx.tcx().item_path_str(*trait_did))) - + err.fileline_help(span, + &*format!("candidate #{}: use `{}`", + i + 1, + fcx.tcx().item_path_str(*trait_did))); } return } @@ -301,13 +314,13 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}, name = item_name); - fcx.sess().fileline_help(span, &msg[..]); + err.fileline_help(span, &msg[..]); for (i, trait_info) in candidates.iter().enumerate() { - fcx.sess().fileline_help(span, - &*format!("candidate #{}: `{}`", - i + 1, - fcx.tcx().item_path_str(trait_info.def_id))) + err.fileline_help(span, + &*format!("candidate #{}: `{}`", + i + 1, + fcx.tcx().item_path_str(trait_info.def_id))); } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 72d0e5b53321e..99a72a4c9df10 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -119,6 +119,7 @@ use syntax::ast; use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::codemap::{self, Span, Spanned}; +use syntax::errors::DiagnosticBuilder; use syntax::parse::token::{self, InternedString}; use syntax::ptr::P; use syntax::util::lev_distance::find_best_match_for_name; @@ -702,11 +703,12 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { for item in &m.items { let pty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(item.id)); if !pty.generics.types.is_empty() { - span_err!(ccx.tcx.sess, item.span, E0044, + let mut err = struct_span_err!(ccx.tcx.sess, item.span, E0044, "foreign items may not have type parameters"); - span_help!(ccx.tcx.sess, item.span, + span_help!(&mut err, item.span, "consider using specialization instead of \ type parameters"); + err.emit(); } if let hir::ForeignItemFn(ref fn_decl, _) = item.node { @@ -1037,7 +1039,7 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, t_expr: Ty<'tcx>, id: ast::NodeId) { let tstr = fcx.infcx().ty_to_string(t_cast); - fcx.type_error_message(span, |actual| { + let mut err = fcx.type_error_struct(span, |actual| { format!("cast to unsized type: `{}` as `{}`", actual, tstr) }, t_expr, None); match t_expr.sty { @@ -1049,16 +1051,16 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, if t_cast.is_trait() { match fcx.tcx().sess.codemap().span_to_snippet(t_span) { Ok(s) => { - fcx.tcx().sess.span_suggestion(t_span, - "try casting to a reference instead:", - format!("&{}{}", mtstr, s)); + err.as_mut().unwrap().span_suggestion(t_span, + "try casting to a reference instead:", + format!("&{}{}", mtstr, s)); }, Err(_) => - span_help!(fcx.tcx().sess, t_span, + span_help!(err.as_mut().unwrap(), t_span, "did you mean `&{}{}`?", mtstr, tstr), } } else { - span_help!(fcx.tcx().sess, span, + span_help!(err.as_mut().unwrap(), span, "consider using an implicit coercion to `&{}{}` instead", mtstr, tstr); } @@ -1066,19 +1068,20 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ty::TyBox(..) => { match fcx.tcx().sess.codemap().span_to_snippet(t_span) { Ok(s) => { - fcx.tcx().sess.span_suggestion(t_span, - "try casting to a `Box` instead:", - format!("Box<{}>", s)); + err.as_mut().unwrap().span_suggestion(t_span, + "try casting to a `Box` instead:", + format!("Box<{}>", s)); }, Err(_) => - span_help!(fcx.tcx().sess, t_span, "did you mean `Box<{}>`?", tstr), + span_help!(err.as_mut().unwrap(), t_span, "did you mean `Box<{}>`?", tstr), } } _ => { - span_help!(fcx.tcx().sess, e_span, + span_help!(err.as_mut().unwrap(), e_span, "consider using a box or reference as appropriate"); } } + err.map(|mut e| e.emit()); fcx.write_error(id); } @@ -1443,10 +1446,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some((adt, variant)) } else if var_kind == ty::VariantKind::Unit { if !self.tcx().sess.features.borrow().braced_empty_structs { - self.tcx().sess.span_err(span, "empty structs and enum variants \ - with braces are unstable"); - fileline_help!(self.tcx().sess, span, "add #![feature(braced_empty_structs)] to \ - the crate features to enable"); + let mut err = self.tcx().sess.struct_span_err(span, + "empty structs and enum variants \ + with braces are unstable"); + fileline_help!(&mut err, span, "add #![feature(braced_empty_structs)] to \ + the crate features to enable"); + err.emit(); } Some((adt, variant)) @@ -1614,12 +1619,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp: Span, mk_msg: M, actual_ty: Ty<'tcx>, - err: Option<&TypeError<'tcx>>) where - M: FnOnce(String) -> String, + err: Option<&TypeError<'tcx>>) + where M: FnOnce(String) -> String, { self.infcx().type_error_message(sp, mk_msg, actual_ty, err); } + pub fn type_error_struct(&self, + sp: Span, + mk_msg: M, + actual_ty: Ty<'tcx>, + err: Option<&TypeError<'tcx>>) + -> Option> + where M: FnOnce(String) -> String, + { + self.infcx().type_error_struct(sp, mk_msg, actual_ty, err) + } + pub fn report_mismatched_types(&self, sp: Span, e: Ty<'tcx>, @@ -2913,7 +2929,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, lvalue_pref: LvaluePreference, base: &'tcx hir::Expr, field: &Spanned) { - let tcx = fcx.ccx.tcx; check_expr_with_lvalue_pref(fcx, base, lvalue_pref); let expr_t = structurally_resolved_type(fcx, expr.span, fcx.expr_ty(base)); @@ -2945,19 +2960,19 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } if method::exists(fcx, field.span, field.node, expr_t, expr.id) { - fcx.type_error_message( - field.span, - |actual| { - format!("attempted to take value of method `{}` on type \ - `{}`", field.node, actual) - }, - expr_t, None); - - tcx.sess.fileline_help(field.span, + fcx.type_error_struct(field.span, + |actual| { + format!("attempted to take value of method `{}` on type \ + `{}`", field.node, actual) + }, + expr_t, None) + .unwrap() + .fileline_help(field.span, "maybe a `()` to call it is missing? \ - If not, try an anonymous function"); + If not, try an anonymous function") + .emit(); } else { - fcx.type_error_message( + fcx.type_error_struct( expr.span, |actual| { format!("attempted access of field `{}` on \ @@ -2966,19 +2981,22 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, field.node, actual) }, - expr_t, None); - if let ty::TyStruct(def, _) = expr_t.sty { - suggest_field_names(def.struct_variant(), field, tcx, vec![]); - } + expr_t, None) + .map(|mut e| { + if let ty::TyStruct(def, _) = expr_t.sty { + suggest_field_names(&mut e, def.struct_variant(), field, vec![]); + } + e.emit(); + }); } fcx.write_error(expr.id); } // displays hints about the closest matches in field names - fn suggest_field_names<'tcx>(variant: ty::VariantDef<'tcx>, + fn suggest_field_names<'tcx>(err: &mut DiagnosticBuilder, + variant: ty::VariantDef<'tcx>, field: &Spanned, - tcx: &ty::ctxt<'tcx>, skip : Vec) { let name = field.node.as_str(); let names = variant.fields @@ -2995,8 +3013,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // only find fits with at least one matching letter if let Some(name) = find_best_match_for_name(names, &name, Some(name.len())) { - tcx.sess.span_help(field.span, - &format!("did you mean `{}`?", name)); + err.span_help(field.span, + &format!("did you mean `{}`?", n)); } } @@ -3071,7 +3089,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, variant: ty::VariantDef<'tcx>, field: &hir::Field, skip_fields: &[hir::Field]) { - fcx.type_error_message( + fcx.type_error_struct( field.name.span, |actual| if let ty::TyEnum(..) = ty.sty { format!("struct variant `{}::{}` has no field named `{}`", @@ -3081,10 +3099,13 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, actual, field.name.node) }, ty, - None); - // prevent all specified fields from being suggested - let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str()); - suggest_field_names(variant, &field.name, fcx.tcx(), skip_fields.collect()); + None) + .map(|mut e| { + // prevent all specified fields from being suggested + let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str()); + suggest_field_names(&mut e, variant, &field.name, skip_fields.collect()); + e.emit(); + }); } fn check_expr_struct_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, @@ -4146,9 +4167,9 @@ pub fn check_representable(tcx: &ty::ctxt, // caught by case 1. match rty.is_representable(tcx, sp) { Representability::SelfRecursive => { - span_err!(tcx.sess, sp, E0072, "invalid recursive {} type", designation); - tcx.sess.fileline_help( - sp, "wrap the inner value in a box to make it representable"); + struct_span_err!(tcx.sess, sp, E0072, "invalid recursive {} type", designation) + .fileline_help(sp, "wrap the inner value in a box to make it representable") + .emit(); return false } Representability::Representable | Representability::ContainsRecursive => (), @@ -4245,11 +4266,12 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, // Check for duplicate discriminant values match disr_vals.iter().position(|&x| x == current_disr_val) { Some(i) => { - span_err!(ccx.tcx.sess, v.span, E0081, + let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0081, "discriminant value `{}` already exists", disr_vals[i]); let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap(); - span_note!(ccx.tcx.sess, ccx.tcx.map.span(variant_i_node_id), - "conflicting discriminant here") + span_note!(&mut err, ccx.tcx.map.span(variant_i_node_id), + "conflicting discriminant here"); + err.emit(); } None => {} } @@ -4258,10 +4280,11 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, attr::ReprAny | attr::ReprExtern => (), attr::ReprInt(sp, ity) => { if !disr_in_range(ccx, ity, current_disr_val) { - span_err!(ccx.tcx.sess, v.span, E0082, + let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0082, "discriminant value outside specified type"); - span_note!(ccx.tcx.sess, sp, + span_note!(&mut err, sp, "discriminant type specified here"); + err.emit(); } } attr::ReprSimd => { diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 0c65f68f02e3e..c5a36fb4ada25 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -187,10 +187,10 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, hir_util::binop_to_string(op.node), lhs_ty); } else { - span_err!(fcx.tcx().sess, lhs_expr.span, E0369, - "binary operation `{}` cannot be applied to type `{}`", - hir_util::binop_to_string(op.node), - lhs_ty); + let mut err = struct_span_err!(fcx.tcx().sess, lhs_expr.span, E0369, + "binary operation `{}` cannot be applied to type `{}`", + hir_util::binop_to_string(op.node), + lhs_ty); let missing_trait = match op.node { hir::BiAdd => Some("std::ops::Add"), hir::BiSub => Some("std::ops::Sub"), @@ -208,10 +208,11 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }; if let Some(missing_trait) = missing_trait { - span_note!(fcx.tcx().sess, lhs_expr.span, + span_note!(&mut err, lhs_expr.span, "an implementation of `{}` might be missing for `{}`", missing_trait, lhs_ty); } + err.emit(); } } fcx.tcx().types.err diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 230422b7044cd..d43efb17b2eff 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -23,6 +23,7 @@ use std::cell::RefCell; use std::collections::HashSet; use syntax::ast; use syntax::codemap::{Span}; +use syntax::errors::DiagnosticBuilder; use syntax::parse::token::{special_idents}; use rustc_front::intravisit::{self, Visitor}; use rustc_front::hir; @@ -496,12 +497,12 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { span: Span, param_name: ast::Name) { - error_392(self.tcx(), span, param_name); + let mut err = error_392(self.tcx(), span, param_name); let suggested_marker_id = self.tcx().lang_items.phantom_data(); match suggested_marker_id { Some(def_id) => { - self.tcx().sess.fileline_help( + err.fileline_help( span, &format!("consider removing `{}` or using a marker such as `{}`", param_name, @@ -511,6 +512,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // no lang items, no help! } } + err.emit(); } } @@ -621,9 +623,10 @@ pub fn error_380<'ccx,'tcx>(ccx: &'ccx CrateCtxt<'ccx, 'tcx>, span: Span) { Trait for ..`) must have no methods or associated items") } -pub fn error_392<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, param_name: ast::Name) { - span_err!(tcx.sess, span, E0392, - "parameter `{}` is never used", param_name); +pub fn error_392<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, param_name: ast::Name) + -> DiagnosticBuilder<'tcx> { + struct_span_err!(tcx.sess, span, E0392, + "parameter `{}` is never used", param_name) } pub fn error_194<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, name: ast::Name) { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index c24a416a0109c..1536f13a1d51a 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -129,13 +129,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { !self.fcx.expr_ty(lhs).references_error() && !self.fcx.expr_ty(rhs).references_error() { - tcx.sess.span_err( - e.span, - "overloaded augmented assignments are not stable"); - fileline_help!( - tcx.sess, e.span, - "add #![feature(augmented_assignments)] to the crate root \ - to enable"); + tcx.sess.struct_span_err(e.span, + "overloaded augmented assignments \ + are not stable") + .fileline_help(e.span, + "add #![feature(augmented_assignments)] to the \ + crate root to enable") + .emit() } } } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 37bbfb4e967f7..02be74a590661 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -502,9 +502,14 @@ fn enforce_trait_manually_implementable(tcx: &ty::ctxt, sp: Span, trait_def_id: } else { return // everything OK }; - span_err!(tcx.sess, sp, E0183, "manual implementations of `{}` are experimental", trait_name); - fileline_help!(tcx.sess, sp, - "add `#![feature(unboxed_closures)]` to the crate attributes to enable"); + let mut err = struct_span_err!(tcx.sess, + sp, + E0183, + "manual implementations of `{}` are experimental", + trait_name); + fileline_help!(&mut err, sp, + "add `#![feature(unboxed_closures)]` to the crate attributes to enable"); + err.emit(); } pub fn check_coherence(crate_context: &CrateCtxt) { diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 411e1a4e480fc..76be04bb1741a 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -48,11 +48,11 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { match lang_def_id { Some(lang_def_id) if lang_def_id == impl_def_id => { /* OK */ }, _ => { - span_err!(self.tcx.sess, span, E0390, + struct_span_err!(self.tcx.sess, span, E0390, "only a single inherent implementation marked with `#[lang = \"{}\"]` \ - is allowed for the `{}` primitive", lang, ty); - span_help!(self.tcx.sess, span, - "consider using a trait to implement these methods"); + is allowed for the `{}` primitive", lang, ty) + .span_help(span, "consider using a trait to implement these methods") + .emit(); } } } diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 7d1f71967a2d5..beb409f7f0f23 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -150,18 +150,19 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { }).unwrap_or(String::new()) }; - span_err!(self.tcx.sess, self.span_of_impl(impl1), E0119, - "conflicting implementations of trait `{}`{}:", - trait_ref, - self_type); + let mut err = struct_span_err!(self.tcx.sess, self.span_of_impl(impl1), E0119, + "conflicting implementations of trait `{}`{}:", + trait_ref, + self_type); if impl2.is_local() { - span_note!(self.tcx.sess, self.span_of_impl(impl2), + span_note!(&mut err, self.span_of_impl(impl2), "conflicting implementation is here:"); } else { let cname = self.tcx.sess.cstore.crate_name(impl2.krate); - self.tcx.sess.note(&format!("conflicting implementation in crate `{}`", cname)); + err.note(&format!("conflicting implementation in crate `{}`", cname)); } + err.emit(); } fn span_of_impl(&self, impl_did: DefId) -> Span { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index b7ce91d331723..eaaa2c773791e 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -225,24 +225,24 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { assert!(!cycle.is_empty()); let tcx = self.tcx; - span_err!(tcx.sess, span, E0391, + let mut err = struct_span_err!(tcx.sess, span, E0391, "unsupported cyclic reference between types/traits detected"); match cycle[0] { AstConvRequest::GetItemTypeScheme(def_id) | AstConvRequest::GetTraitDef(def_id) => { - tcx.sess.note( + err.note( &format!("the cycle begins when processing `{}`...", tcx.item_path_str(def_id))); } AstConvRequest::EnsureSuperPredicates(def_id) => { - tcx.sess.note( + err.note( &format!("the cycle begins when computing the supertraits of `{}`...", tcx.item_path_str(def_id))); } AstConvRequest::GetTypeParameterBounds(id) => { let def = tcx.type_parameter_def(id); - tcx.sess.note( + err.note( &format!("the cycle begins when computing the bounds \ for type parameter `{}`...", def.name)); @@ -253,18 +253,18 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { match *request { AstConvRequest::GetItemTypeScheme(def_id) | AstConvRequest::GetTraitDef(def_id) => { - tcx.sess.note( + err.note( &format!("...which then requires processing `{}`...", tcx.item_path_str(def_id))); } AstConvRequest::EnsureSuperPredicates(def_id) => { - tcx.sess.note( + err.note( &format!("...which then requires computing the supertraits of `{}`...", tcx.item_path_str(def_id))); } AstConvRequest::GetTypeParameterBounds(id) => { let def = tcx.type_parameter_def(id); - tcx.sess.note( + err.note( &format!("...which then requires computing the bounds \ for type parameter `{}`...", def.name)); @@ -275,24 +275,25 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { match cycle[0] { AstConvRequest::GetItemTypeScheme(def_id) | AstConvRequest::GetTraitDef(def_id) => { - tcx.sess.note( + err.note( &format!("...which then again requires processing `{}`, completing the cycle.", tcx.item_path_str(def_id))); } AstConvRequest::EnsureSuperPredicates(def_id) => { - tcx.sess.note( + err.note( &format!("...which then again requires computing the supertraits of `{}`, \ completing the cycle.", tcx.item_path_str(def_id))); } AstConvRequest::GetTypeParameterBounds(id) => { let def = tcx.type_parameter_def(id); - tcx.sess.note( + err.note( &format!("...which then again requires computing the bounds \ for type parameter `{}`, completing the cycle.", def.name)); } } + err.emit(); } /// Loads the trait def for a given trait, returning ErrorReported if a cycle arises. @@ -1012,10 +1013,11 @@ fn convert_struct_variant<'tcx>(tcx: &ty::ctxt<'tcx>, hir::NamedField(name, vis) => { let dup_span = seen_fields.get(&name).cloned(); if let Some(prev_span) = dup_span { - span_err!(tcx.sess, f.span, E0124, - "field `{}` is already declared", - name); - span_note!(tcx.sess, prev_span, "previously declared here"); + let mut err = struct_span_err!(tcx.sess, f.span, E0124, + "field `{}` is already declared", + name); + span_note!(&mut err, prev_span, "previously declared here"); + err.emit(); } else { seen_fields.insert(name, f.span); } @@ -1080,12 +1082,13 @@ fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>, None }, Err(err) => { - span_err!(tcx.sess, err.span, E0080, - "constant evaluation error: {}", - err.description()); + let mut diag = struct_span_err!(tcx.sess, err.span, E0080, + "constant evaluation error: {}", + err.description()); if !e.span.contains(err.span) { - tcx.sess.span_note(e.span, "for enum discriminant here"); + diag.span_note(e.span, "for enum discriminant here"); } + diag.emit(); None } } @@ -1254,13 +1257,14 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar"); if paren_sugar && !ccx.tcx.sess.features.borrow().unboxed_closures { - ccx.tcx.sess.span_err( + let mut err = ccx.tcx.sess.struct_span_err( it.span, "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \ which traits can use parenthetical notation"); - fileline_help!(ccx.tcx.sess, it.span, + fileline_help!(&mut err, it.span, "add `#![feature(unboxed_closures)]` to \ the crate attributes to use it"); + err.emit(); } let substs = ccx.tcx.mk_substs(mk_trait_substs(ccx, generics)); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 70c6d6f05c66a..bf890f3e50709 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -203,8 +203,9 @@ fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>, match result { Ok(_) => true, Err(ref terr) => { - span_err!(tcx.sess, span, E0211, "{}: {}", msg(), terr); - tcx.note_and_explain_type_err(terr, span); + let mut err = struct_span_err!(tcx.sess, span, E0211, "{}: {}", msg(), terr); + tcx.note_and_explain_type_err(&mut err, terr, span); + err.emit(); false } } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 26662605ba87f..96d0052cf1801 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -305,8 +305,10 @@ pub fn find_export_name_attr(diag: &Handler, attrs: &[Attribute]) -> Option ({ + __diagnostic_used!($code); + $session.span_warn_with_code($span, &format!($($message)*), stringify!($code)) + }) +} + #[macro_export] macro_rules! span_err_or_warn { ($is_warning:expr, $session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ @@ -43,31 +51,59 @@ macro_rules! span_err_or_warn { } #[macro_export] -macro_rules! span_warn { +macro_rules! struct_span_fatal { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ __diagnostic_used!($code); - $session.span_warn_with_code($span, &format!($($message)*), stringify!($code)) + $session.struct_span_fatal_with_code($span, &format!($($message)*), stringify!($code)) + }) +} + +#[macro_export] +macro_rules! struct_span_err { + ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ + __diagnostic_used!($code); + $session.struct_span_err_with_code($span, &format!($($message)*), stringify!($code)) + }) +} + +#[macro_export] +macro_rules! struct_span_warn { + ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ + __diagnostic_used!($code); + $session.struct_span_warn_with_code($span, &format!($($message)*), stringify!($code)) + }) +} + +#[macro_export] +macro_rules! struct_span_err_or_warn { + ($is_warning:expr, $session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ + __diagnostic_used!($code); + if $is_warning { + $session.struct_span_warn_with_code($span, &format!($($message)*), stringify!($code)) + } else { + $session.struct_span_err_with_code($span, &format!($($message)*), stringify!($code)) + } }) } #[macro_export] macro_rules! span_note { - ($session:expr, $span:expr, $($message:tt)*) => ({ - ($session).span_note($span, &format!($($message)*)) + ($err:expr, $span:expr, $($message:tt)*) => ({ + ($err).span_note($span, &format!($($message)*)); }) } #[macro_export] macro_rules! span_help { - ($session:expr, $span:expr, $($message:tt)*) => ({ - ($session).span_help($span, &format!($($message)*)) + ($err:expr, $span:expr, $($message:tt)*) => ({ + ($err).span_help($span, &format!($($message)*)); }) } #[macro_export] macro_rules! fileline_help { - ($session:expr, $span:expr, $($message:tt)*) => ({ - ($session).fileline_help($span, &format!($($message)*)) + ($err:expr, $span:expr, $($message:tt)*) => ({ + ($err).fileline_help($span, &format!($($message)*)); }) } diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index be0d5729c7009..d17ca3892dc68 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -62,10 +62,10 @@ pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt, match diagnostics.get_mut(&code.name) { // Previously used errors. Some(&mut ErrorInfo { description: _, use_site: Some(previous_span) }) => { - ecx.span_warn(span, &format!( + ecx.struct_span_warn(span, &format!( "diagnostic code {} already used", code - )); - ecx.span_note(previous_span, "previous invocation"); + )).span_note(previous_span, "previous invocation") + .emit(); } // Newly used errors. Some(ref mut info) => { diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 990e4bb421d57..8b9df7aa92130 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -30,7 +30,7 @@ pub trait Emitter { // Emit a structured diagnostic. fn emit_struct(&mut self, db: &DiagnosticBuilder) { - self.emit(db.span, db.message, db.code.as_ref().map(|s| &**s), db.level); + self.emit(db.span, &db.message, db.code.as_ref().map(|s| &**s), db.level); for child in &db.children { match child.render_span { Some(ref sp) => self.custom_emit(sp.clone(), &child.message, child.level), diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index f616420218e1a..fc0f1925207ae 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -14,6 +14,7 @@ use ast; use ast::Name; use codemap; use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION}; +use errors::DiagnosticBuilder; use ext; use ext::expand; use ext::tt::macro_rules; @@ -678,6 +679,25 @@ impl<'a> ExtCtxt<'a> { } } + pub fn struct_span_warn(&self, + sp: Span, + msg: &str) + -> DiagnosticBuilder<'a> { + self.parse_sess.span_diagnostic.struct_span_warn(sp, msg) + } + pub fn struct_span_err(&self, + sp: Span, + msg: &str) + -> DiagnosticBuilder<'a> { + self.parse_sess.span_diagnostic.struct_span_err(sp, msg) + } + pub fn struct_span_fatal(&self, + sp: Span, + msg: &str) + -> DiagnosticBuilder<'a> { + self.parse_sess.span_diagnostic.struct_span_fatal(sp, msg) + } + /// Emit `msg` attached to `sp`, and stop compilation immediately. /// /// `span_err` should be strongly preferred where-ever possible: @@ -710,15 +730,6 @@ impl<'a> ExtCtxt<'a> { pub fn span_bug(&self, sp: Span, msg: &str) -> ! { self.parse_sess.span_diagnostic.span_bug(sp, msg); } - pub fn span_note(&self, sp: Span, msg: &str) { - self.parse_sess.span_diagnostic.span_note(sp, msg); - } - pub fn span_help(&self, sp: Span, msg: &str) { - self.parse_sess.span_diagnostic.span_help(sp, msg); - } - pub fn fileline_help(&self, sp: Span, msg: &str) { - self.parse_sess.span_diagnostic.fileline_help(sp, msg); - } pub fn bug(&self, msg: &str) -> ! { self.parse_sess.span_diagnostic.bug(msg); } @@ -743,10 +754,13 @@ impl<'a> ExtCtxt<'a> { token::intern(st) } - pub fn suggest_macro_name(&mut self, name: &str, span: Span) { + pub fn suggest_macro_name(&mut self, + name: &str, + span: Span, + err: &mut DiagnosticBuilder<'a>) { let names = &self.syntax_env.names; if let Some(suggestion) = find_best_match_for_name(names.iter(), name, None) { - self.fileline_help(span, &format!("did you mean `{}!`?", suggestion)); + err.fileline_help(span, &format!("did you mean `{}!`?", suggestion)); } } } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 743bcda18def4..5f27bdfc98a41 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -201,11 +201,12 @@ fn expand_mac_invoc(mac: ast::Mac, let extname = pth.segments[0].identifier.name; match fld.cx.syntax_env.find(extname) { None => { - fld.cx.span_err( + let mut err = fld.cx.struct_span_err( pth.span, &format!("macro undefined: '{}!'", &extname)); - fld.cx.suggest_macro_name(&extname.as_str(), pth.span); + fld.cx.suggest_macro_name(&extname.as_str(), pth.span, &mut err); + err.emit(); // let compilation continue None @@ -334,11 +335,15 @@ fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool for attr in attrs { let mut is_use = attr.check_name("macro_use"); if attr.check_name("macro_escape") { - fld.cx.span_warn(attr.span, "macro_escape is a deprecated synonym for macro_use"); + let mut err = + fld.cx.struct_span_warn(attr.span, + "macro_escape is a deprecated synonym for macro_use"); is_use = true; if let ast::AttrStyle::Inner = attr.node.style { - fld.cx.fileline_help(attr.span, "consider an outer attribute, \ - #[macro_use] mod ..."); + err.fileline_help(attr.span, "consider an outer attribute, \ + #[macro_use] mod ...").emit(); + } else { + err.emit(); } }; diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 0c3a8b05fba1e..7a1a207a562a1 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -802,7 +802,7 @@ fn parse_arguments_to_quote(cx: &ExtCtxt, tts: &[TokenTree]) let cx_expr = panictry!(p.parse_expr()); if !panictry!(p.eat(&token::Comma)) { - panic!(p.fatal("expected token `,`")); + let _ = p.diagnostic().fatal("expected token `,`"); } let tts = panictry!(p.parse_all_token_trees()); diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 7899e170ecf19..f00224bacdd2d 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -117,11 +117,9 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree while self.p.token != token::Eof { match panictry!(self.p.parse_item()) { Some(item) => ret.push(item), - None => panic!(self.p.span_fatal( - self.p.span, - &format!("expected item, found `{}`", - self.p.this_token_to_string()) - )) + None => panic!(self.p.diagnostic().span_fatal(self.p.span, + &format!("expected item, found `{}`", + self.p.this_token_to_string()))) } } Some(ret) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index fb09118035c7e..166d32a8cc62f 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -82,6 +82,7 @@ use ast; use ast::{TokenTree, Name, Ident}; use codemap::{BytePos, mk_sp, Span, Spanned}; use codemap; +use errors::FatalError; use parse::lexer::*; //resolve bug? use parse::ParseSess; use parse::parser::{LifetimeAndTypesWithoutColons, Parser}; @@ -499,11 +500,12 @@ pub fn parse(sess: &ParseSess, } } -pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal { +pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { match name { "tt" => { p.quote_depth += 1; //but in theory, non-quoted tts might be useful - let res = token::NtTT(P(panictry!(p.parse_token_tree()))); + let res: ::parse::PResult<'a, _> = p.parse_token_tree(); + let res = token::NtTT(P(panictry!(res))); p.quote_depth -= 1; return res; } @@ -514,12 +516,18 @@ pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal { match name { "item" => match panictry!(p.parse_item()) { Some(i) => token::NtItem(i), - None => panic!(p.fatal("expected an item keyword")) + None => { + p.fatal("expected an item keyword").emit(); + panic!(FatalError); + } }, "block" => token::NtBlock(panictry!(p.parse_block())), "stmt" => match panictry!(p.parse_stmt()) { Some(s) => token::NtStmt(s), - None => panic!(p.fatal("expected a statement")) + None => { + p.fatal("expected a statement").emit(); + panic!(FatalError); + } }, "pat" => token::NtPat(panictry!(p.parse_pat())), "expr" => token::NtExpr(panictry!(p.parse_expr())), @@ -532,8 +540,9 @@ pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal { } _ => { let token_str = pprust::token_to_string(&p.token); - panic!(p.fatal(&format!("expected ident, found {}", - &token_str[..]))) + p.fatal(&format!("expected ident, found {}", + &token_str[..])).emit(); + panic!(FatalError) } }, "path" => { @@ -541,11 +550,12 @@ pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal { }, "meta" => token::NtMeta(panictry!(p.parse_meta_item())), _ => { - panic!(p.span_fatal_help(sp, - &format!("invalid fragment specifier `{}`", name), - "valid fragment specifiers are `ident`, `block`, \ - `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \ - and `item`")) + p.span_fatal_help(sp, + &format!("invalid fragment specifier `{}`", name), + "valid fragment specifiers are `ident`, `block`, \ + `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \ + and `item`").emit(); + panic!(FatalError); } } } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index fae60d2803293..fd0bbf7a0723e 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -55,12 +55,12 @@ impl<'a> ParserAnyMacro<'a> { following", token_str); let span = parser.span; - parser.span_err(span, &msg[..]); - + let mut err = parser.diagnostic().struct_span_err(span, &msg[..]); let msg = format!("caused by the macro expansion here; the usage \ of `{}!` is likely invalid in {} context", self.macro_ident, context); - parser.span_note(self.site_span, &msg[..]); + err.span_note(self.site_span, &msg[..]) + .emit(); } } } @@ -111,7 +111,10 @@ impl<'a> MacResult for ParserAnyMacro<'a> { Some(stmt) => ret.push(stmt), None => (), }, - Err(_) => break, + Err(mut e) => { + e.emit(); + break; + } } } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 4ea0fd76fea4a..a23dc3b8871fa 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -725,17 +725,21 @@ pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIs GateIssue::Library(lib) => lib, }; - if let Some(n) = issue { - diag.span_err(span, &format!("{} (see issue #{})", explain, n)); + let mut err = if let Some(n) = issue { + diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n)) } else { - diag.span_err(span, explain); - } + diag.struct_span_err(span, explain) + }; // #23973: do not suggest `#![feature(...)]` if we are in beta/stable - if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { return; } - diag.fileline_help(span, &format!("add #![feature({})] to the \ - crate attributes to enable", - feature)); + if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { + err.emit(); + return; + } + err.fileline_help(span, &format!("add #![feature({})] to the \ + crate attributes to enable", + feature)); + err.emit(); } pub const EXPLAIN_ASM: &'static str = @@ -942,11 +946,13 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { self.gate_feature("braced_empty_structs", span, "empty structs and enum variants with braces are unstable"); } else if s.is_tuple() { - self.context.span_handler.span_err(span, "empty tuple structs and enum variants \ - are not allowed, use unit structs and \ - enum variants instead"); - self.context.span_handler.span_help(span, "remove trailing `()` to make a unit \ - struct or unit enum variant"); + self.context.span_handler.struct_span_err(span, "empty tuple structs and enum \ + variants are not allowed, use \ + unit structs and enum variants \ + instead") + .span_help(span, "remove trailing `()` to make a unit \ + struct or unit enum variant") + .emit(); } } visit::walk_struct_def(self, s) diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index c09e35f1077a5..795f4044f6eb1 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -40,17 +40,22 @@ extern crate libc; extern crate serialize as rustc_serialize; // used by deriving -// A variant of 'try!' that panics on Err(FatalError). This is used as a -// crutch on the way towards a non-panic!-prone parser. It should be used -// for fatal parsing errors; eventually we plan to convert all code using -// panictry to just use normal try +// A variant of 'try!' that panics on an Err. This is used as a crutch on the +// way towards a non-panic!-prone parser. It should be used for fatal parsing +// errors; eventually we plan to convert all code using panictry to just use +// normal try. +// Exported for syntax_ext, not meant for general use. +#[macro_export] macro_rules! panictry { ($e:expr) => ({ use std::result::Result::{Ok, Err}; - use errors::FatalError; + use $crate::errors::FatalError; match $e { Ok(e) => e, - Err(FatalError) => panic!(FatalError) + Err(mut e) => { + e.emit(); + panic!(FatalError); + } } }) } diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 5df2478d48758..35ec3dcb0fd5f 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -19,7 +19,7 @@ use ptr::P; impl<'a> Parser<'a> { /// Parse attributes that appear before an item - pub fn parse_outer_attributes(&mut self) -> PResult> { + pub fn parse_outer_attributes(&mut self) -> PResult<'a, Vec> { let mut attrs: Vec = Vec::new(); loop { debug!("parse_outer_attributes: self.token={:?}", @@ -51,7 +51,7 @@ impl<'a> Parser<'a> { /// /// If permit_inner is true, then a leading `!` indicates an inner /// attribute - pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult { + pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> { debug!("parse_attributes: permit_inner={:?} self.token={:?}", permit_inner, self.token); let (span, value, mut style) = match self.token { @@ -64,11 +64,13 @@ impl<'a> Parser<'a> { try!(self.bump()); if !permit_inner { let span = self.span; - self.span_err(span, - "an inner attribute is not permitted in \ - this context"); - self.fileline_help(span, - "place inner attribute at the top of the module or block"); + self.diagnostic().struct_span_err(span, + "an inner attribute is not permitted in \ + this context") + .fileline_help(span, + "place inner attribute at the top of \ + the module or block") + .emit() } ast::AttrStyle::Inner } else { @@ -111,7 +113,7 @@ impl<'a> Parser<'a> { /// terminated by a semicolon. /// matches inner_attrs* - pub fn parse_inner_attributes(&mut self) -> PResult> { + pub fn parse_inner_attributes(&mut self) -> PResult<'a, Vec> { let mut attrs: Vec = vec![]; loop { match self.token { @@ -146,7 +148,7 @@ impl<'a> Parser<'a> { /// matches meta_item = IDENT /// | IDENT = lit /// | IDENT meta_seq - pub fn parse_meta_item(&mut self) -> PResult> { + pub fn parse_meta_item(&mut self) -> PResult<'a, P> { let nt_meta = match self.token { token::Interpolated(token::NtMeta(ref e)) => { Some(e.clone()) @@ -195,10 +197,10 @@ impl<'a> Parser<'a> { } /// matches meta_seq = ( COMMASEP(meta_item) ) - fn parse_meta_seq(&mut self) -> PResult>> { + fn parse_meta_seq(&mut self) -> PResult<'a, Vec>> { self.parse_unspanned_seq(&token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), seq_sep_trailing_allowed(token::Comma), - |p| p.parse_meta_item()) + |p: &mut Parser<'a>| p.parse_meta_item()) } } diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 4619410ada727..3d8f3bcd5268f 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -11,7 +11,7 @@ use ast; use codemap::{BytePos, CharPos, CodeMap, Pos, Span}; use codemap; -use errors::{FatalError, Handler}; +use errors::{FatalError, Handler, DiagnosticBuilder}; use ext::tt::transcribe::tt_next_token; use parse::token::str_to_ident; use parse::token; @@ -173,10 +173,6 @@ impl<'a> StringReader<'a> { self.span_diagnostic.span_err(sp, m) } - /// Suggest some help with a given span. - pub fn help_span(&self, sp: Span, m: &str) { - self.span_diagnostic.span_help(sp, m) - } /// Report a fatal error spanning [`from_pos`, `to_pos`). fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> FatalError { @@ -188,11 +184,6 @@ impl<'a> StringReader<'a> { self.err_span(codemap::mk_sp(from_pos, to_pos), m) } - /// Suggest some help spanning [`from_pos`, `to_pos`). - fn help_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) { - self.help_span(codemap::mk_sp(from_pos, to_pos), m) - } - /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an /// escaped character to the error message fn fatal_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) -> FatalError { @@ -201,6 +192,17 @@ impl<'a> StringReader<'a> { for c in c.escape_default() { m.push(c) } self.fatal_span_(from_pos, to_pos, &m[..]) } + fn struct_fatal_span_char(&self, + from_pos: BytePos, + to_pos: BytePos, + m: &str, + c: char) + -> DiagnosticBuilder<'a> { + let mut m = m.to_string(); + m.push_str(": "); + for c in c.escape_default() { m.push(c) } + self.span_diagnostic.struct_span_fatal(codemap::mk_sp(from_pos, to_pos), &m[..]) + } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an /// escaped character to the error message @@ -210,6 +212,17 @@ impl<'a> StringReader<'a> { for c in c.escape_default() { m.push(c) } self.err_span_(from_pos, to_pos, &m[..]); } + fn struct_err_span_char(&self, + from_pos: BytePos, + to_pos: BytePos, + m: &str, + c: char) + -> DiagnosticBuilder<'a> { + let mut m = m.to_string(); + m.push_str(": "); + for c in c.escape_default() { m.push(c) } + self.span_diagnostic.struct_span_err(codemap::mk_sp(from_pos, to_pos), &m[..]) + } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending the /// offending string to the error message @@ -746,10 +759,12 @@ impl<'a> StringReader<'a> { let valid = if self.curr_is('{') { self.scan_unicode_escape(delim) && !ascii_only } else { - self.err_span_(start, self.last_pos, - "incorrect unicode escape sequence"); - self.help_span_(start, self.last_pos, - "format of unicode escape sequences is `\\u{…}`"); + let span = codemap::mk_sp(start, self.last_pos); + self.span_diagnostic.struct_span_err(span, + "incorrect unicode escape sequence") + .span_help(span, + "format of unicode escape sequences is `\\u{…}`") + .emit(); false }; if ascii_only { @@ -771,21 +786,22 @@ impl<'a> StringReader<'a> { } c => { let last_pos = self.last_pos; - self.err_span_char( + let mut err = self.struct_err_span_char( escaped_pos, last_pos, if ascii_only { "unknown byte escape" } else { "unknown character escape" }, c); if e == '\r' { - self.help_span_(escaped_pos, last_pos, + err.span_help(codemap::mk_sp(escaped_pos, last_pos), "this is an isolated carriage return; consider checking \ - your editor and version control settings") + your editor and version control settings"); } if (e == '{' || e == '}') && !ascii_only { - self.help_span_(escaped_pos, last_pos, + err.span_help(codemap::mk_sp(escaped_pos, last_pos), "if used in a formatting string, \ - curly braces are escaped with `{{` and `}}`") + curly braces are escaped with `{{` and `}}`"); } + err.emit(); false } } @@ -1224,8 +1240,13 @@ impl<'a> StringReader<'a> { c => { let last_bpos = self.last_pos; let bpos = self.pos; - unicode_chars::check_for_substitution(&self, c); - panic!(self.fatal_span_char(last_bpos, bpos, "unknown start of token", c)) + let mut err = self.struct_fatal_span_char(last_bpos, + bpos, + "unknown start of token", + c); + unicode_chars::check_for_substitution(&self, c, &mut err); + err.emit(); + panic!(FatalError); } } } diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs index a2f37426210e9..1d32dd4973127 100644 --- a/src/libsyntax/parse/lexer/unicode_chars.rs +++ b/src/libsyntax/parse/lexer/unicode_chars.rs @@ -12,6 +12,7 @@ // http://www.unicode.org/Public/security/revision-06/confusables.txt use codemap::mk_sp as make_span; +use errors::DiagnosticBuilder; use super::StringReader; const UNICODE_ARRAY: &'static [(char, &'static str, char)] = &[ @@ -179,7 +180,9 @@ const ASCII_ARRAY: &'static [(char, &'static str)] = &[ ('=', "Equals Sign"), ('>', "Greater-Than Sign"), ]; -pub fn check_for_substitution(reader: &StringReader, ch: char) { +pub fn check_for_substitution<'a>(reader: &StringReader<'a>, + ch: char, + err: &mut DiagnosticBuilder<'a>) { UNICODE_ARRAY .iter() .find(|&&(c, _, _)| c == ch) @@ -190,7 +193,7 @@ pub fn check_for_substitution(reader: &StringReader, ch: char) { let msg = format!("unicode character '{}' ({}) looks much like '{}' ({}), but it's not", ch, u_name, ascii_char, ascii_name); - reader.help_span(span, &msg); + err.span_help(span, &msg); }, None => { reader diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 6951d6319acaf..efbde0f85a6b5 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -12,7 +12,7 @@ use ast; use codemap::{self, Span, CodeMap, FileMap}; -use errors::{Handler, ColorConfig, FatalError}; +use errors::{Handler, ColorConfig, DiagnosticBuilder}; use parse::parser::Parser; use parse::token::InternedString; use ptr::P; @@ -25,7 +25,7 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; use std::str; -pub type PResult = Result; +pub type PResult<'a, T> = Result>; #[macro_use] pub mod parser; @@ -76,8 +76,8 @@ pub fn parse_crate_from_file( cfg: ast::CrateConfig, sess: &ParseSess ) -> ast::Crate { - panictry!(new_parser_from_file(sess, cfg, input).parse_crate_mod()) - // why is there no p.abort_if_errors here? + let mut parser = new_parser_from_file(sess, cfg, input); + abort_if_errors(parser.parse_crate_mod(), &parser) } pub fn parse_crate_attrs_from_file( @@ -85,8 +85,8 @@ pub fn parse_crate_attrs_from_file( cfg: ast::CrateConfig, sess: &ParseSess ) -> Vec { - // FIXME: maybe_aborted? - panictry!(new_parser_from_file(sess, cfg, input).parse_inner_attributes()) + let mut parser = new_parser_from_file(sess, cfg, input); + abort_if_errors(parser.parse_inner_attributes(), &parser) } pub fn parse_crate_from_source_str(name: String, @@ -271,6 +271,20 @@ pub fn maybe_aborted(result: T, p: Parser) -> T { result } +fn abort_if_errors<'a, T>(result: PResult<'a, T>, p: &Parser) -> T { + match result { + Ok(c) => { + p.abort_if_errors(); + c + } + Err(mut e) => { + e.emit(); + p.abort_if_errors(); + unreachable!(); + } + } +} + /// Parse a string representing a character literal into its final form. /// Rather than just accepting/rejecting a given literal, unescapes it as /// well. Can take any slice prefixed by a character escape. Returns the @@ -449,11 +463,13 @@ fn filtered_float_lit(data: token::InternedString, suffix: Option<&str>, Some(suf) => { if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) { // if it looks like a width, lets try to be helpful. - sd.span_err(sp, &format!("invalid width `{}` for float literal", &suf[1..])); - sd.fileline_help(sp, "valid widths are 32 and 64"); + sd.struct_span_err(sp, &format!("invalid width `{}` for float literal", &suf[1..])) + .fileline_help(sp, "valid widths are 32 and 64") + .emit(); } else { - sd.span_err(sp, &format!("invalid suffix `{}` for float literal", suf)); - sd.fileline_help(sp, "valid suffixes are `f32` and `f64`"); + sd.struct_span_err(sp, &format!("invalid suffix `{}` for float literal", suf)) + .fileline_help(sp, "valid suffixes are `f32` and `f64`") + .emit(); } ast::LitFloatUnsuffixed(data) @@ -622,13 +638,15 @@ pub fn integer_lit(s: &str, // i and u look like widths, so lets // give an error message along those lines if looks_like_width_suffix(&['i', 'u'], suf) { - sd.span_err(sp, &format!("invalid width `{}` for integer literal", - &suf[1..])); - sd.fileline_help(sp, "valid widths are 8, 16, 32 and 64"); + sd.struct_span_err(sp, &format!("invalid width `{}` for integer literal", + &suf[1..])) + .fileline_help(sp, "valid widths are 8, 16, 32 and 64") + .emit(); } else { - sd.span_err(sp, &format!("invalid suffix `{}` for numeric literal", suf)); - sd.fileline_help(sp, "the suffix must be one of the integral types \ - (`u32`, `isize`, etc)"); + sd.struct_span_err(sp, &format!("invalid suffix `{}` for numeric literal", suf)) + .fileline_help(sp, "the suffix must be one of the integral types \ + (`u32`, `isize`, etc)") + .emit(); } ty diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index 5dba1e189ab15..75f1ac49c9acc 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -59,18 +59,17 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> { kind_str: &str, desc: &str, error: bool) { - if error { - self.span_err(sp, &format!("obsolete syntax: {}", kind_str)); + let mut err = if error { + self.diagnostic().struct_span_err(sp, &format!("obsolete syntax: {}", kind_str)) } else { - self.span_warn(sp, &format!("obsolete syntax: {}", kind_str)); - } + self.diagnostic().struct_span_warn(sp, &format!("obsolete syntax: {}", kind_str)) + }; if !self.obsolete_set.contains(&kind) && (error || self.sess.span_diagnostic.can_emit_warnings) { - self.sess - .span_diagnostic - .note(&format!("{}", desc)); + err.note(&format!("{}", desc)); self.obsolete_set.insert(kind); } + err.emit(); } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index dbd34b49f7d9e..f31f24cf249f1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -60,7 +60,7 @@ use attr::{ThinAttributes, ThinAttributesExt, AttributesExt}; use ast; use ast_util::{self, ident_to_path}; use codemap::{self, Span, BytePos, Spanned, spanned, mk_sp, CodeMap}; -use errors::{self, FatalError}; +use errors::{self, DiagnosticBuilder}; use ext::tt::macro_parser; use parse; use parse::classify; @@ -392,14 +392,14 @@ impl<'a> Parser<'a> { Parser::token_to_string(&self.token) } - pub fn unexpected_last(&self, t: &token::Token) -> FatalError { + pub fn unexpected_last(&self, t: &token::Token) -> DiagnosticBuilder<'a> { let token_str = Parser::token_to_string(t); let last_span = self.last_span; self.span_fatal(last_span, &format!("unexpected token: `{}`", token_str)) } - pub fn unexpected(&mut self) -> FatalError { + pub fn unexpected(&mut self) -> DiagnosticBuilder<'a> { match self.expect_one_of(&[], &[]) { Err(e) => e, Ok(_) => unreachable!() @@ -408,7 +408,7 @@ impl<'a> Parser<'a> { /// Expect and consume the token t. Signal an error if /// the next token is not t. - pub fn expect(&mut self, t: &token::Token) -> PResult<()> { + pub fn expect(&mut self, t: &token::Token) -> PResult<'a, ()> { if self.expected_tokens.is_empty() { if self.token == *t { self.bump() @@ -429,7 +429,7 @@ impl<'a> Parser<'a> { /// anything. Signal a fatal error if next token is unexpected. pub fn expect_one_of(&mut self, edible: &[token::Token], - inedible: &[token::Token]) -> PResult<()>{ + inedible: &[token::Token]) -> PResult<'a, ()>{ fn tokens_to_string(tokens: &[TokenType]) -> String { let mut i = tokens.iter(); // This might be a sign we need a connect method on Iterator. @@ -484,7 +484,7 @@ impl<'a> Parser<'a> { /// true if and only if input was consumed for recovery. pub fn check_for_erroneous_unit_struct_expecting(&mut self, expected: &[token::Token]) - -> PResult { + -> PResult<'a, bool> { if self.token == token::OpenDelim(token::Brace) && expected.iter().all(|t| *t != token::OpenDelim(token::Brace)) && self.look_ahead(1, |t| *t == token::CloseDelim(token::Brace)) { @@ -504,7 +504,7 @@ impl<'a> Parser<'a> { /// followed by some token from the set edible + inedible. Recover /// from anticipated input errors, discarding erroneous characters. pub fn commit_expr(&mut self, e: &Expr, edible: &[token::Token], - inedible: &[token::Token]) -> PResult<()> { + inedible: &[token::Token]) -> PResult<'a, ()> { debug!("commit_expr {:?}", e); if let ExprPath(..) = e.node { // might be unit-struct construction; check for recoverableinput error. @@ -517,7 +517,7 @@ impl<'a> Parser<'a> { self.expect_one_of(edible, inedible) } - pub fn commit_expr_expecting(&mut self, e: &Expr, edible: token::Token) -> PResult<()> { + pub fn commit_expr_expecting(&mut self, e: &Expr, edible: token::Token) -> PResult<'a, ()> { self.commit_expr(e, &[edible], &[]) } @@ -525,7 +525,7 @@ impl<'a> Parser<'a> { /// followed by some token from the set edible + inedible. Check /// for recoverable input errors, discarding erroneous characters. pub fn commit_stmt(&mut self, edible: &[token::Token], - inedible: &[token::Token]) -> PResult<()> { + inedible: &[token::Token]) -> PResult<'a, ()> { if self.last_token .as_ref() .map_or(false, |t| t.is_ident() || t.is_path()) { @@ -538,11 +538,11 @@ impl<'a> Parser<'a> { self.expect_one_of(edible, inedible) } - pub fn commit_stmt_expecting(&mut self, edible: token::Token) -> PResult<()> { + pub fn commit_stmt_expecting(&mut self, edible: token::Token) -> PResult<'a, ()> { self.commit_stmt(&[edible], &[]) } - pub fn parse_ident(&mut self) -> PResult { + pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> { self.check_strict_keywords(); try!(self.check_reserved_keywords()); match self.token { @@ -561,7 +561,7 @@ impl<'a> Parser<'a> { } } - pub fn parse_ident_or_self_type(&mut self) -> PResult { + pub fn parse_ident_or_self_type(&mut self) -> PResult<'a, ast::Ident> { if self.is_self_type_ident() { self.expect_self_type_ident() } else { @@ -569,7 +569,7 @@ impl<'a> Parser<'a> { } } - pub fn parse_path_list_item(&mut self) -> PResult { + pub fn parse_path_list_item(&mut self) -> PResult<'a, ast::PathListItem> { let lo = self.span.lo; let node = if try!(self.eat_keyword(keywords::SelfValue)) { let rename = try!(self.parse_rename()); @@ -595,7 +595,7 @@ impl<'a> Parser<'a> { /// Consume token 'tok' if it exists. Returns true if the given /// token was present, false otherwise. - pub fn eat(&mut self, tok: &token::Token) -> PResult { + pub fn eat(&mut self, tok: &token::Token) -> PResult<'a, bool> { let is_present = self.check(tok); if is_present { try!(self.bump())} Ok(is_present) @@ -608,7 +608,7 @@ impl<'a> Parser<'a> { /// If the next token is the given keyword, eat it and return /// true. Otherwise, return false. - pub fn eat_keyword(&mut self, kw: keywords::Keyword) -> PResult { + pub fn eat_keyword(&mut self, kw: keywords::Keyword) -> PResult<'a, bool> { if self.check_keyword(kw) { try!(self.bump()); Ok(true) @@ -617,7 +617,7 @@ impl<'a> Parser<'a> { } } - pub fn eat_keyword_noexpect(&mut self, kw: keywords::Keyword) -> PResult { + pub fn eat_keyword_noexpect(&mut self, kw: keywords::Keyword) -> PResult<'a, bool> { if self.token.is_keyword(kw) { try!(self.bump()); Ok(true) @@ -629,7 +629,7 @@ impl<'a> Parser<'a> { /// If the given word is not a keyword, signal an error. /// If the next token is not the given word, signal an error. /// Otherwise, eat it. - pub fn expect_keyword(&mut self, kw: keywords::Keyword) -> PResult<()> { + pub fn expect_keyword(&mut self, kw: keywords::Keyword) -> PResult<'a, ()> { if !try!(self.eat_keyword(kw) ){ self.expect_one_of(&[], &[]) } else { @@ -649,11 +649,10 @@ impl<'a> Parser<'a> { } /// Signal an error if the current token is a reserved keyword - pub fn check_reserved_keywords(&mut self) -> PResult<()>{ + pub fn check_reserved_keywords(&mut self) -> PResult<'a, ()>{ if self.token.is_reserved_keyword() { let token_str = self.this_token_to_string(); - Err(self.fatal(&format!("`{}` is a reserved keyword", - token_str))) + Err(self.fatal(&format!("`{}` is a reserved keyword", token_str))) } else { Ok(()) } @@ -661,7 +660,7 @@ impl<'a> Parser<'a> { /// Expect and consume an `&`. If `&&` is seen, replace it with a single /// `&` and continue. If an `&` is not seen, signal an error. - fn expect_and(&mut self) -> PResult<()> { + fn expect_and(&mut self) -> PResult<'a, ()> { self.expected_tokens.push(TokenType::Token(token::BinOp(token::And))); match self.token { token::BinOp(token::And) => self.bump(), @@ -693,7 +692,7 @@ impl<'a> Parser<'a> { /// /// This is meant to be used when parsing generics on a path to get the /// starting token. - fn eat_lt(&mut self) -> PResult { + fn eat_lt(&mut self) -> PResult<'a, bool> { self.expected_tokens.push(TokenType::Token(token::Lt)); match self.token { token::Lt => { try!(self.bump()); Ok(true)} @@ -707,7 +706,7 @@ impl<'a> Parser<'a> { } } - fn expect_lt(&mut self) -> PResult<()> { + fn expect_lt(&mut self) -> PResult<'a, ()> { if !try!(self.eat_lt()) { self.expect_one_of(&[], &[]) } else { @@ -718,7 +717,7 @@ impl<'a> Parser<'a> { /// Expect and consume a GT. if a >> is seen, replace it /// with a single > and continue. If a GT is not seen, /// signal an error. - pub fn expect_gt(&mut self) -> PResult<()> { + pub fn expect_gt(&mut self) -> PResult<'a, ()> { self.expected_tokens.push(TokenType::Token(token::Gt)); match self.token { token::Gt => self.bump(), @@ -750,8 +749,8 @@ impl<'a> Parser<'a> { pub fn parse_seq_to_before_gt_or_return(&mut self, sep: Option, mut f: F) - -> PResult<(P<[T]>, bool)> where - F: FnMut(&mut Parser) -> PResult>, + -> PResult<'a, (P<[T]>, bool)> where + where F: FnMut(&mut Parser<'a>) -> PResult<'a, Option>, { let mut v = Vec::new(); // This loop works by alternating back and forth between parsing types @@ -788,8 +787,8 @@ impl<'a> Parser<'a> { pub fn parse_seq_to_before_gt(&mut self, sep: Option, mut f: F) - -> PResult> where - F: FnMut(&mut Parser) -> PResult, + -> PResult<'a, P<[T]>> where + F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, { let (result, returned) = try!(self.parse_seq_to_before_gt_or_return(sep, |p| Ok(Some(try!(f(p)))))); @@ -800,8 +799,8 @@ impl<'a> Parser<'a> { pub fn parse_seq_to_gt(&mut self, sep: Option, f: F) - -> PResult> where - F: FnMut(&mut Parser) -> PResult, + -> PResult<'a, P<[T]>> where + F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, { let v = try!(self.parse_seq_to_before_gt(sep, f)); try!(self.expect_gt()); @@ -811,8 +810,8 @@ impl<'a> Parser<'a> { pub fn parse_seq_to_gt_or_return(&mut self, sep: Option, f: F) - -> PResult<(P<[T]>, bool)> where - F: FnMut(&mut Parser) -> PResult>, + -> PResult<'a, (P<[T]>, bool)> where + F: FnMut(&mut Parser<'a>) -> PResult<'a, Option>, { let (v, returned) = try!(self.parse_seq_to_before_gt_or_return(sep, f)); if !returned { @@ -828,8 +827,8 @@ impl<'a> Parser<'a> { ket: &token::Token, sep: SeqSep, f: F) - -> PResult> where - F: FnMut(&mut Parser) -> PResult, + -> PResult<'a, Vec> where + F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, { let val = try!(self.parse_seq_to_before_end(ket, sep, f)); try!(self.bump()); @@ -843,8 +842,8 @@ impl<'a> Parser<'a> { ket: &token::Token, sep: SeqSep, mut f: F) - -> PResult> where - F: FnMut(&mut Parser) -> PResult, + -> PResult<'a, Vec> where + F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, { let mut first: bool = true; let mut v = vec!(); @@ -870,8 +869,8 @@ impl<'a> Parser<'a> { ket: &token::Token, sep: SeqSep, f: F) - -> PResult> where - F: FnMut(&mut Parser) -> PResult, + -> PResult<'a, Vec> where + F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, { try!(self.expect(bra)); let result = try!(self.parse_seq_to_before_end(ket, sep, f)); @@ -886,8 +885,8 @@ impl<'a> Parser<'a> { ket: &token::Token, sep: SeqSep, f: F) - -> PResult> where - F: FnMut(&mut Parser) -> PResult, + -> PResult<'a, Vec> where + F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, { let result = try!(self.parse_unspanned_seq(bra, ket, sep, f)); if result.is_empty() { @@ -905,8 +904,8 @@ impl<'a> Parser<'a> { ket: &token::Token, sep: SeqSep, f: F) - -> PResult>> where - F: FnMut(&mut Parser) -> PResult, + -> PResult<'a, Spanned>> where + F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, { let lo = self.span.lo; try!(self.expect(bra)); @@ -917,7 +916,7 @@ impl<'a> Parser<'a> { } /// Advance the parser by one token - pub fn bump(&mut self) -> PResult<()> { + pub fn bump(&mut self) -> PResult<'a, ()> { self.last_span = self.span; // Stash token for error recovery (sometimes; clone is not necessarily cheap). self.last_token = if self.token.is_ident() || @@ -950,7 +949,7 @@ impl<'a> Parser<'a> { } /// Advance the parser by one token and return the bumped token. - pub fn bump_and_get(&mut self) -> PResult { + pub fn bump_and_get(&mut self) -> PResult<'a, token::Token> { let old_token = mem::replace(&mut self.token, token::Underscore); try!(self.bump()); Ok(old_token) @@ -981,28 +980,16 @@ impl<'a> Parser<'a> { } f(&self.buffer[((self.buffer_start + dist - 1) & 3) as usize].tok) } - pub fn fatal(&self, m: &str) -> errors::FatalError { - self.sess.span_diagnostic.span_fatal(self.span, m) + pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> { + self.sess.span_diagnostic.struct_span_fatal(self.span, m) } - pub fn span_fatal(&self, sp: Span, m: &str) -> errors::FatalError { - self.sess.span_diagnostic.span_fatal(sp, m) + pub fn span_fatal(&self, sp: Span, m: &str) -> DiagnosticBuilder<'a> { + self.sess.span_diagnostic.struct_span_fatal(sp, m) } - pub fn span_fatal_help(&self, sp: Span, m: &str, help: &str) -> errors::FatalError { - self.span_err(sp, m); - self.fileline_help(sp, help); - errors::FatalError - } - pub fn span_note(&self, sp: Span, m: &str) { - self.sess.span_diagnostic.span_note(sp, m) - } - pub fn span_help(&self, sp: Span, m: &str) { - self.sess.span_diagnostic.span_help(sp, m) - } - pub fn span_suggestion(&self, sp: Span, m: &str, n: String) { - self.sess.span_diagnostic.span_suggestion(sp, m, n) - } - pub fn fileline_help(&self, sp: Span, m: &str) { - self.sess.span_diagnostic.fileline_help(sp, m) + pub fn span_fatal_help(&self, sp: Span, m: &str, help: &str) -> DiagnosticBuilder<'a> { + let mut err = self.sess.span_diagnostic.struct_span_fatal(sp, m); + err.fileline_help(sp, help); + err } pub fn bug(&self, m: &str) -> ! { self.sess.span_diagnostic.span_bug(self.span, m) @@ -1023,6 +1010,10 @@ impl<'a> Parser<'a> { self.sess.span_diagnostic.abort_if_errors(); } + pub fn diagnostic(&self) -> &'a errors::Handler { + &self.sess.span_diagnostic + } + pub fn id_to_interned_str(&mut self, id: Ident) -> InternedString { id.name.as_str() } @@ -1042,7 +1033,7 @@ impl<'a> Parser<'a> { } } - pub fn parse_for_in_type(&mut self) -> PResult { + pub fn parse_for_in_type(&mut self) -> PResult<'a, Ty_> { /* Parses whatever can come after a `for` keyword in a type. The `for` has already been consumed. @@ -1085,12 +1076,12 @@ impl<'a> Parser<'a> { } } - pub fn parse_ty_path(&mut self) -> PResult { + pub fn parse_ty_path(&mut self) -> PResult<'a, Ty_> { Ok(TyPath(None, try!(self.parse_path(LifetimeAndTypesWithoutColons)))) } /// parse a TyBareFn type: - pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec) -> PResult { + pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec) -> PResult<'a, Ty_> { /* [unsafe] [extern "ABI"] fn <'lt> (S) -> T @@ -1127,7 +1118,7 @@ impl<'a> Parser<'a> { } /// Parses an obsolete closure kind (`&:`, `&mut:`, or `:`). - pub fn parse_obsolete_closure_kind(&mut self) -> PResult<()> { + pub fn parse_obsolete_closure_kind(&mut self) -> PResult<'a, ()> { let lo = self.span.lo; if self.check(&token::BinOp(token::And)) && @@ -1156,7 +1147,7 @@ impl<'a> Parser<'a> { Ok(()) } - pub fn parse_unsafety(&mut self) -> PResult { + pub fn parse_unsafety(&mut self) -> PResult<'a, Unsafety> { if try!(self.eat_keyword(keywords::Unsafe)) { return Ok(Unsafety::Unsafe); } else { @@ -1165,12 +1156,12 @@ impl<'a> Parser<'a> { } /// Parse the items in a trait declaration - pub fn parse_trait_items(&mut self) -> PResult>> { + pub fn parse_trait_items(&mut self) -> PResult<'a, Vec>> { self.parse_unspanned_seq( &token::OpenDelim(token::Brace), &token::CloseDelim(token::Brace), seq_sep_none(), - |p| -> PResult> { + |p| -> PResult<'a, P> { maybe_whole!(no_clone p, NtTraitItem); let mut attrs = try!(p.parse_outer_attributes()); let lo = p.span.lo; @@ -1200,7 +1191,7 @@ impl<'a> Parser<'a> { let ident = try!(p.parse_ident()); let mut generics = try!(p.parse_generics()); - let (explicit_self, d) = try!(p.parse_fn_decl_with_self(|p|{ + let (explicit_self, d) = try!(p.parse_fn_decl_with_self(|p: &mut Parser<'a>|{ // This is somewhat dubious; We don't want to allow // argument names to be left off if there is a // definition... @@ -1251,14 +1242,14 @@ impl<'a> Parser<'a> { } /// Parse a possibly mutable type - pub fn parse_mt(&mut self) -> PResult { + pub fn parse_mt(&mut self) -> PResult<'a, MutTy> { let mutbl = try!(self.parse_mutability()); let t = try!(self.parse_ty()); Ok(MutTy { ty: t, mutbl: mutbl }) } /// Parse optional return type [ -> TY ] in function decl - pub fn parse_ret_ty(&mut self) -> PResult { + pub fn parse_ret_ty(&mut self) -> PResult<'a, FunctionRetTy> { if try!(self.eat(&token::RArrow) ){ if try!(self.eat(&token::Not) ){ Ok(NoReturn(self.last_span)) @@ -1272,7 +1263,7 @@ impl<'a> Parser<'a> { } /// Parse a type in a context where `T1+T2` is allowed. - pub fn parse_ty_sum(&mut self) -> PResult> { + pub fn parse_ty_sum(&mut self) -> PResult<'a, P> { let lo = self.span.lo; let lhs = try!(self.parse_ty()); @@ -1297,7 +1288,7 @@ impl<'a> Parser<'a> { } /// Parse a type. - pub fn parse_ty(&mut self) -> PResult> { + pub fn parse_ty(&mut self) -> PResult<'a, P> { maybe_whole!(no_clone self, NtTy); let lo = self.span.lo; @@ -1397,7 +1388,7 @@ impl<'a> Parser<'a> { Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: t, span: sp})) } - pub fn parse_borrowed_pointee(&mut self) -> PResult { + pub fn parse_borrowed_pointee(&mut self) -> PResult<'a, Ty_> { // look for `&'lt` or `&'foo ` and interpret `foo` as the region name: let opt_lifetime = try!(self.parse_opt_lifetime()); @@ -1405,7 +1396,7 @@ impl<'a> Parser<'a> { return Ok(TyRptr(opt_lifetime, mt)); } - pub fn parse_ptr(&mut self) -> PResult { + pub fn parse_ptr(&mut self) -> PResult<'a, MutTy> { let mutbl = if try!(self.eat_keyword(keywords::Mut) ){ MutMutable } else if try!(self.eat_keyword(keywords::Const) ){ @@ -1443,7 +1434,7 @@ impl<'a> Parser<'a> { /// This version of parse arg doesn't necessarily require /// identifier names. - pub fn parse_arg_general(&mut self, require_name: bool) -> PResult { + pub fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> { maybe_whole!(no_clone self, NtArg); let pat = if require_name || self.is_named_argument() { @@ -1470,12 +1461,12 @@ impl<'a> Parser<'a> { } /// Parse a single function argument - pub fn parse_arg(&mut self) -> PResult { + pub fn parse_arg(&mut self) -> PResult<'a, Arg> { self.parse_arg_general(true) } /// Parse an argument in a lambda header e.g. |arg, arg| - pub fn parse_fn_block_arg(&mut self) -> PResult { + pub fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> { let pat = try!(self.parse_pat()); let t = if try!(self.eat(&token::Colon) ){ try!(self.parse_ty_sum()) @@ -1493,7 +1484,7 @@ impl<'a> Parser<'a> { }) } - pub fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult>> { + pub fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option>> { if self.check(&token::Semi) { try!(self.bump()); Ok(Some(try!(self.parse_expr()))) @@ -1503,7 +1494,7 @@ impl<'a> Parser<'a> { } /// Matches token_lit = LIT_INTEGER | ... - pub fn lit_from_token(&self, tok: &token::Token) -> PResult { + pub fn lit_from_token(&self, tok: &token::Token) -> PResult<'a, Lit_> { match *tok { token::Interpolated(token::NtExpr(ref v)) => { match v.node { @@ -1562,7 +1553,7 @@ impl<'a> Parser<'a> { } /// Matches lit = true | false | token_lit - pub fn parse_lit(&mut self) -> PResult { + pub fn parse_lit(&mut self) -> PResult<'a, Lit> { let lo = self.span.lo; let lit = if try!(self.eat_keyword(keywords::True) ){ LitBool(true) @@ -1577,7 +1568,7 @@ impl<'a> Parser<'a> { } /// matches '-' lit | lit - pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult> { + pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult<'a, P> { let minus_lo = self.span.lo; let minus_present = try!(self.eat(&token::BinOp(token::Minus))); let lo = self.span.lo; @@ -1610,7 +1601,7 @@ impl<'a> Parser<'a> { /// `::a` /// `::F::a::` pub fn parse_qualified_path(&mut self, mode: PathParsingMode) - -> PResult<(QSelf, ast::Path)> { + -> PResult<'a, (QSelf, ast::Path)> { let span = self.last_span; let self_type = try!(self.parse_ty_sum()); let mut path = if try!(self.eat_keyword(keywords::As)) { @@ -1653,7 +1644,7 @@ impl<'a> Parser<'a> { /// mode. The `mode` parameter determines whether lifetimes, types, and/or /// bounds are permitted and whether `::` must precede type parameter /// groups. - pub fn parse_path(&mut self, mode: PathParsingMode) -> PResult { + pub fn parse_path(&mut self, mode: PathParsingMode) -> PResult<'a, ast::Path> { // Check for a whole path... let found = match self.token { token::Interpolated(token::NtPath(_)) => Some(try!(self.bump_and_get())), @@ -1696,7 +1687,7 @@ impl<'a> Parser<'a> { /// - `a::b::c` /// - `a::b::c(V) -> W` /// - `a::b::c(V)` - pub fn parse_path_segments_without_colons(&mut self) -> PResult> { + pub fn parse_path_segments_without_colons(&mut self) -> PResult<'a, Vec> { let mut segments = Vec::new(); loop { // First, parse an identifier. @@ -1749,7 +1740,7 @@ impl<'a> Parser<'a> { /// Examples: /// - `a::b::::c` - pub fn parse_path_segments_with_colons(&mut self) -> PResult> { + pub fn parse_path_segments_with_colons(&mut self) -> PResult<'a, Vec> { let mut segments = Vec::new(); loop { // First, parse an identifier. @@ -1794,7 +1785,7 @@ impl<'a> Parser<'a> { /// Examples: /// - `a::b::c` - pub fn parse_path_segments_without_types(&mut self) -> PResult> { + pub fn parse_path_segments_without_types(&mut self) -> PResult<'a, Vec> { let mut segments = Vec::new(); loop { // First, parse an identifier. @@ -1814,7 +1805,7 @@ impl<'a> Parser<'a> { } /// parses 0 or 1 lifetime - pub fn parse_opt_lifetime(&mut self) -> PResult> { + pub fn parse_opt_lifetime(&mut self) -> PResult<'a, Option> { match self.token { token::Lifetime(..) => { Ok(Some(try!(self.parse_lifetime()))) @@ -1827,7 +1818,7 @@ impl<'a> Parser<'a> { /// Parses a single lifetime /// Matches lifetime = LIFETIME - pub fn parse_lifetime(&mut self) -> PResult { + pub fn parse_lifetime(&mut self) -> PResult<'a, ast::Lifetime> { match self.token { token::Lifetime(i) => { let span = self.span; @@ -1846,7 +1837,7 @@ impl<'a> Parser<'a> { /// Parses `lifetime_defs = [ lifetime_defs { ',' lifetime_defs } ]` where `lifetime_def = /// lifetime [':' lifetimes]` - pub fn parse_lifetime_defs(&mut self) -> PResult> { + pub fn parse_lifetime_defs(&mut self) -> PResult<'a, Vec> { let mut res = Vec::new(); loop { @@ -1889,7 +1880,7 @@ impl<'a> Parser<'a> { /// Parses zero or more comma separated lifetimes. Expects each lifetime to be followed by /// either a comma or `>`. Used when parsing type parameter lists, where we expect something /// like `<'a, 'b, T>`. - pub fn parse_lifetimes(&mut self, sep: token::Token) -> PResult> { + pub fn parse_lifetimes(&mut self, sep: token::Token) -> PResult<'a, Vec> { let mut res = Vec::new(); loop { @@ -1911,7 +1902,7 @@ impl<'a> Parser<'a> { } /// Parse mutability declaration (mut/const/imm) - pub fn parse_mutability(&mut self) -> PResult { + pub fn parse_mutability(&mut self) -> PResult<'a, Mutability> { if try!(self.eat_keyword(keywords::Mut) ){ Ok(MutMutable) } else { @@ -1920,7 +1911,7 @@ impl<'a> Parser<'a> { } /// Parse ident COLON expr - pub fn parse_field(&mut self) -> PResult { + pub fn parse_field(&mut self) -> PResult<'a, Field> { let lo = self.span.lo; let i = try!(self.parse_ident()); let hi = self.last_span.hi; @@ -2012,7 +2003,7 @@ impl<'a> Parser<'a> { }) } - fn expect_open_delim(&mut self) -> PResult { + fn expect_open_delim(&mut self) -> PResult<'a, token::DelimToken> { self.expected_tokens.push(TokenType::Token(token::Gt)); match self.token { token::OpenDelim(delim) => { @@ -2030,7 +2021,7 @@ impl<'a> Parser<'a> { /// NB: This does not parse outer attributes, /// and is private because it only works /// correctly if called from parse_dot_or_call_expr(). - fn parse_bottom_expr(&mut self) -> PResult> { + fn parse_bottom_expr(&mut self) -> PResult<'a, P> { maybe_whole_expr!(self); // Outer attributes are already parsed and will be @@ -2294,7 +2285,7 @@ impl<'a> Parser<'a> { fn parse_or_use_outer_attributes(&mut self, already_parsed_attrs: Option) - -> PResult { + -> PResult<'a, ThinAttributes> { if let Some(attrs) = already_parsed_attrs { Ok(attrs) } else { @@ -2305,7 +2296,7 @@ impl<'a> Parser<'a> { /// Parse a block or unsafe block pub fn parse_block_expr(&mut self, lo: BytePos, blk_mode: BlockCheckMode, attrs: ThinAttributes) - -> PResult> { + -> PResult<'a, P> { let outer_attrs = attrs; try!(self.expect(&token::OpenDelim(token::Brace))); @@ -2320,7 +2311,7 @@ impl<'a> Parser<'a> { /// parse a.b or a(13) or a[4] or just a pub fn parse_dot_or_call_expr(&mut self, already_parsed_attrs: Option) - -> PResult> { + -> PResult<'a, P> { let attrs = try!(self.parse_or_use_outer_attributes(already_parsed_attrs)); let b = try!(self.parse_bottom_expr()); @@ -2330,7 +2321,7 @@ impl<'a> Parser<'a> { pub fn parse_dot_or_call_expr_with(&mut self, e0: P, attrs: ThinAttributes) - -> PResult> { + -> PResult<'a, P> { // Stitch the list of outer attributes onto the return value. // A little bit ugly, but the best way given the current code // structure @@ -2356,7 +2347,7 @@ impl<'a> Parser<'a> { ) } - fn parse_dot_or_call_expr_with_(&mut self, e0: P) -> PResult> { + fn parse_dot_or_call_expr_with_(&mut self, e0: P) -> PResult<'a, P> { let mut e = e0; let lo = e.span.lo; let mut hi; @@ -2437,18 +2428,19 @@ impl<'a> Parser<'a> { try!(self.bump()); let last_span = self.last_span; let fstr = n.as_str(); - self.span_err(last_span, - &format!("unexpected token: `{}`", n.as_str())); + let mut err = self.diagnostic().struct_span_err(last_span, + &format!("unexpected token: `{}`", n.as_str())); if fstr.chars().all(|x| "0123456789.".contains(x)) { let float = match fstr.parse::().ok() { Some(f) => f, None => continue, }; - self.fileline_help(last_span, + err.fileline_help(last_span, &format!("try parenthesizing the first index; e.g., `(foo.{}){}`", float.trunc() as usize, format!(".{}", fstr.splitn(2, ".").last().unwrap()))); } + err.emit(); self.abort_if_errors(); } @@ -2489,7 +2481,7 @@ impl<'a> Parser<'a> { } // Parse unquoted tokens after a `$` in a token tree - fn parse_unquoted(&mut self) -> PResult { + fn parse_unquoted(&mut self) -> PResult<'a, TokenTree> { let mut sp = self.span; let (name, namep) = match self.token { token::Dollar => { @@ -2541,7 +2533,7 @@ impl<'a> Parser<'a> { } } - pub fn check_unknown_macro_variable(&mut self) -> PResult<()> { + pub fn check_unknown_macro_variable(&mut self) -> PResult<'a, ()> { if self.quote_depth == 0 { match self.token { token::SubstNt(name, _) => @@ -2555,8 +2547,9 @@ impl<'a> Parser<'a> { /// Parse an optional separator followed by a Kleene-style /// repetition token (+ or *). - pub fn parse_sep_and_kleene_op(&mut self) -> PResult<(Option, ast::KleeneOp)> { - fn parse_kleene_op(parser: &mut Parser) -> PResult> { + pub fn parse_sep_and_kleene_op(&mut self) + -> PResult<'a, (Option, ast::KleeneOp)> { + fn parse_kleene_op<'a>(parser: &mut Parser<'a>) -> PResult<'a, Option> { match parser.token { token::BinOp(token::Star) => { try!(parser.bump()); @@ -2583,7 +2576,7 @@ impl<'a> Parser<'a> { } /// parse a single token tree from the input. - pub fn parse_token_tree(&mut self) -> PResult { + pub fn parse_token_tree(&mut self) -> PResult<'a, TokenTree> { // FIXME #6994: currently, this is too eager. It // parses token trees but also identifies TokenType::Sequence's // and token::SubstNt's; it's too early to know yet @@ -2596,20 +2589,20 @@ impl<'a> Parser<'a> { // not an EOF, and not the desired right-delimiter (if // it were, parse_seq_to_before_end would have prevented // reaching this point. - fn parse_non_delim_tt_tok(p: &mut Parser) -> PResult { + fn parse_non_delim_tt_tok<'b>(p: &mut Parser<'b>) -> PResult<'b, TokenTree> { maybe_whole!(deref p, NtTT); match p.token { token::CloseDelim(_) => { + let token_str = p.this_token_to_string(); + let mut err = p.fatal( + &format!("incorrect close delimiter: `{}`", token_str)); // This is a conservative error: only report the last unclosed delimiter. The // previous unclosed delimiters could actually be closed! The parser just hasn't // gotten to them yet. - match p.open_braces.last() { - None => {} - Some(&sp) => p.span_note(sp, "unclosed delimiter"), + if let Some(&sp) = p.open_braces.last() { + err.span_note(sp, "unclosed delimiter"); }; - let token_str = p.this_token_to_string(); - Err(p.fatal(&format!("incorrect close delimiter: `{}`", - token_str))) + Err(err) }, /* we ought to allow different depths of unquotation */ token::Dollar | token::SubstNt(..) if p.quote_depth > 0 => { @@ -2624,12 +2617,12 @@ impl<'a> Parser<'a> { match self.token { token::Eof => { let open_braces = self.open_braces.clone(); + let mut err: DiagnosticBuilder<'a> = + self.fatal("this file contains an un-closed delimiter"); for sp in &open_braces { - self.span_help(*sp, "did you mean to close this delimiter?"); + err.span_help(*sp, "did you mean to close this delimiter?"); } - // There shouldn't really be a span, but it's easier for the test runner - // if we give it one - return Err(self.fatal("this file contains an un-closed delimiter ")); + return Err(err); }, token::OpenDelim(delim) => { // The span for beginning of the delimited section @@ -2668,7 +2661,7 @@ impl<'a> Parser<'a> { // parse a stream of tokens into a list of TokenTree's, // up to EOF. - pub fn parse_all_token_trees(&mut self) -> PResult> { + pub fn parse_all_token_trees(&mut self) -> PResult<'a, Vec> { let mut tts = Vec::new(); while self.token != token::Eof { tts.push(try!(self.parse_token_tree())); @@ -2679,7 +2672,7 @@ impl<'a> Parser<'a> { /// Parse a prefix-unary-operator expr pub fn parse_prefix_expr(&mut self, already_parsed_attrs: Option) - -> PResult> { + -> PResult<'a, P> { let attrs = try!(self.parse_or_use_outer_attributes(already_parsed_attrs)); let lo = self.span.lo; let hi; @@ -2740,7 +2733,7 @@ impl<'a> Parser<'a> { /// the expression. pub fn parse_assoc_expr(&mut self, already_parsed_attrs: Option) - -> PResult> { + -> PResult<'a, P> { self.parse_assoc_expr_with(0, already_parsed_attrs.into()) } @@ -2748,7 +2741,7 @@ impl<'a> Parser<'a> { pub fn parse_assoc_expr_with(&mut self, min_prec: usize, lhs: LhsExpr) - -> PResult> { + -> PResult<'a, P> { let mut lhs = if let LhsExpr::AlreadyParsed(expr) = lhs { expr } else { @@ -2879,12 +2872,13 @@ impl<'a> Parser<'a> { ExprBinary(op, _, _) if op.node.is_comparison() => { // respan to include both operators let op_span = mk_sp(op.span.lo, self.span.hi); - self.span_err(op_span, + let mut err = self.diagnostic().struct_span_err(op_span, "chained comparison operators require parentheses"); if op.node == BiLt && *outer_op == AssocOp::Greater { - self.fileline_help(op_span, + err.fileline_help(op_span, "use `::<...>` instead of `<...>` if you meant to specify type arguments"); } + err.emit(); } _ => {} } @@ -2893,7 +2887,7 @@ impl<'a> Parser<'a> { /// Parse prefix-forms of range notation: `..expr` and `..` fn parse_prefix_range_expr(&mut self, already_parsed_attrs: Option) - -> PResult> { + -> PResult<'a, P> { debug_assert!(self.token == token::DotDot); let attrs = try!(self.parse_or_use_outer_attributes(already_parsed_attrs)); let lo = self.span.lo; @@ -2928,7 +2922,7 @@ impl<'a> Parser<'a> { } /// Parse an 'if' or 'if let' expression ('if' token already eaten) - pub fn parse_if_expr(&mut self, attrs: ThinAttributes) -> PResult> { + pub fn parse_if_expr(&mut self, attrs: ThinAttributes) -> PResult<'a, P> { if self.check_keyword(keywords::Let) { return self.parse_if_let_expr(attrs); } @@ -2947,7 +2941,7 @@ impl<'a> Parser<'a> { /// Parse an 'if let' expression ('if' token already eaten) pub fn parse_if_let_expr(&mut self, attrs: ThinAttributes) - -> PResult> { + -> PResult<'a, P> { let lo = self.last_span.lo; try!(self.expect_keyword(keywords::Let)); let pat = try!(self.parse_pat()); @@ -2967,7 +2961,7 @@ impl<'a> Parser<'a> { pub fn parse_lambda_expr(&mut self, lo: BytePos, capture_clause: CaptureClause, attrs: ThinAttributes) - -> PResult> + -> PResult<'a, P> { let decl = try!(self.parse_fn_block_decl()); let body = match decl.output { @@ -2997,7 +2991,7 @@ impl<'a> Parser<'a> { } // `else` token already eaten - pub fn parse_else_expr(&mut self) -> PResult> { + pub fn parse_else_expr(&mut self) -> PResult<'a, P> { if try!(self.eat_keyword(keywords::If) ){ return self.parse_if_expr(None); } else { @@ -3009,7 +3003,7 @@ impl<'a> Parser<'a> { /// Parse a 'for' .. 'in' expression ('for' token already eaten) pub fn parse_for_expr(&mut self, opt_ident: Option, span_lo: BytePos, - attrs: ThinAttributes) -> PResult> { + attrs: ThinAttributes) -> PResult<'a, P> { // Parse: `for in ` let pat = try!(self.parse_pat()); @@ -3028,7 +3022,7 @@ impl<'a> Parser<'a> { /// Parse a 'while' or 'while let' expression ('while' token already eaten) pub fn parse_while_expr(&mut self, opt_ident: Option, span_lo: BytePos, - attrs: ThinAttributes) -> PResult> { + attrs: ThinAttributes) -> PResult<'a, P> { if self.token.is_keyword(keywords::Let) { return self.parse_while_let_expr(opt_ident, span_lo, attrs); } @@ -3043,7 +3037,7 @@ impl<'a> Parser<'a> { /// Parse a 'while let' expression ('while' token already eaten) pub fn parse_while_let_expr(&mut self, opt_ident: Option, span_lo: BytePos, - attrs: ThinAttributes) -> PResult> { + attrs: ThinAttributes) -> PResult<'a, P> { try!(self.expect_keyword(keywords::Let)); let pat = try!(self.parse_pat()); try!(self.expect(&token::Eq)); @@ -3057,7 +3051,7 @@ impl<'a> Parser<'a> { // parse `loop {...}`, `loop` token already eaten pub fn parse_loop_expr(&mut self, opt_ident: Option, span_lo: BytePos, - attrs: ThinAttributes) -> PResult> { + attrs: ThinAttributes) -> PResult<'a, P> { let (iattrs, body) = try!(self.parse_inner_attrs_and_block()); let attrs = attrs.append(iattrs.into_thin_attrs()); let hi = body.span.hi; @@ -3065,14 +3059,15 @@ impl<'a> Parser<'a> { } // `match` token already eaten - fn parse_match_expr(&mut self, attrs: ThinAttributes) -> PResult> { + fn parse_match_expr(&mut self, attrs: ThinAttributes) -> PResult<'a, P> { let match_span = self.last_span; let lo = self.last_span.lo; let discriminant = try!(self.parse_expr_res( Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)); - if let Err(e) = self.commit_expr_expecting(&*discriminant, token::OpenDelim(token::Brace)) { + if let Err(mut e) = self.commit_expr_expecting(&*discriminant, + token::OpenDelim(token::Brace)) { if self.token == token::Token::Semi { - self.span_note(match_span, "did you mean to remove this `match` keyword?"); + e.span_note(match_span, "did you mean to remove this `match` keyword?"); } return Err(e) } @@ -3087,7 +3082,7 @@ impl<'a> Parser<'a> { return Ok(self.mk_expr(lo, hi, ExprMatch(discriminant, arms), attrs)); } - pub fn parse_arm(&mut self) -> PResult { + pub fn parse_arm(&mut self) -> PResult<'a, Arm> { maybe_whole!(no_clone self, NtArm); let attrs = try!(self.parse_outer_attributes()); @@ -3118,15 +3113,16 @@ impl<'a> Parser<'a> { } /// Parse an expression - pub fn parse_expr(&mut self) -> PResult> { + pub fn parse_expr(&mut self) -> PResult<'a, P> { self.parse_expr_res(Restrictions::empty(), None) } /// Evaluate the closure with restrictions in place. /// /// After the closure is evaluated, restrictions are reset. - pub fn with_res(&mut self, r: Restrictions, f: F) -> PResult> - where F: FnOnce(&mut Self) -> PResult> { + pub fn with_res(&mut self, r: Restrictions, f: F) -> PResult<'a, P> + where F: FnOnce(&mut Self) -> PResult<'a, P> + { let old = self.restrictions; self.restrictions = r; let r = f(self); @@ -3138,12 +3134,12 @@ impl<'a> Parser<'a> { /// Parse an expression, subject to the given restrictions pub fn parse_expr_res(&mut self, r: Restrictions, already_parsed_attrs: Option) - -> PResult> { + -> PResult<'a, P> { self.with_res(r, |this| this.parse_assoc_expr(already_parsed_attrs)) } /// Parse the RHS of a local variable declaration (e.g. '= 14;') - fn parse_initializer(&mut self) -> PResult>> { + fn parse_initializer(&mut self) -> PResult<'a, Option>> { if self.check(&token::Eq) { try!(self.bump()); Ok(Some(try!(self.parse_expr()))) @@ -3153,7 +3149,7 @@ impl<'a> Parser<'a> { } /// Parse patterns, separated by '|' s - fn parse_pats(&mut self) -> PResult>> { + fn parse_pats(&mut self) -> PResult<'a, Vec>> { let mut pats = Vec::new(); loop { pats.push(try!(self.parse_pat())); @@ -3162,7 +3158,7 @@ impl<'a> Parser<'a> { }; } - fn parse_pat_tuple_elements(&mut self) -> PResult>> { + fn parse_pat_tuple_elements(&mut self) -> PResult<'a, Vec>> { let mut fields = vec![]; if !self.check(&token::CloseDelim(token::Paren)) { fields.push(try!(self.parse_pat())); @@ -3181,7 +3177,7 @@ impl<'a> Parser<'a> { fn parse_pat_vec_elements( &mut self, - ) -> PResult<(Vec>, Option>, Vec>)> { + ) -> PResult<'a, (Vec>, Option>, Vec>)> { let mut before = Vec::new(); let mut slice = None; let mut after = Vec::new(); @@ -3233,7 +3229,7 @@ impl<'a> Parser<'a> { } /// Parse the fields of a struct-like pattern - fn parse_pat_fields(&mut self) -> PResult<(Vec> , bool)> { + fn parse_pat_fields(&mut self) -> PResult<'a, (Vec> , bool)> { let mut fields = Vec::new(); let mut etc = false; let mut first = true; @@ -3310,7 +3306,7 @@ impl<'a> Parser<'a> { return Ok((fields, etc)); } - fn parse_pat_range_end(&mut self) -> PResult> { + fn parse_pat_range_end(&mut self) -> PResult<'a, P> { if self.is_path_start() { let lo = self.span.lo; let (qself, path) = if try!(self.eat_lt()) { @@ -3336,7 +3332,7 @@ impl<'a> Parser<'a> { } /// Parse a pattern. - pub fn parse_pat(&mut self) -> PResult> { + pub fn parse_pat(&mut self) -> PResult<'a, P> { maybe_whole!(self, NtPat); let lo = self.span.lo; @@ -3496,7 +3492,7 @@ impl<'a> Parser<'a> { /// error message when parsing mistakes like ref foo(a,b) fn parse_pat_ident(&mut self, binding_mode: ast::BindingMode) - -> PResult { + -> PResult<'a, ast::Pat_> { if !self.token.is_plain_ident() { let span = self.span; let tok_str = self.this_token_to_string(); @@ -3529,7 +3525,7 @@ impl<'a> Parser<'a> { } /// Parse a local variable declaration - fn parse_local(&mut self, attrs: ThinAttributes) -> PResult> { + fn parse_local(&mut self, attrs: ThinAttributes) -> PResult<'a, P> { let lo = self.span.lo; let pat = try!(self.parse_pat()); @@ -3549,7 +3545,7 @@ impl<'a> Parser<'a> { } /// Parse a "let" stmt - fn parse_let(&mut self, attrs: ThinAttributes) -> PResult> { + fn parse_let(&mut self, attrs: ThinAttributes) -> PResult<'a, P> { let lo = self.span.lo; let local = try!(self.parse_local(attrs)); Ok(P(spanned(lo, self.last_span.hi, DeclLocal(local)))) @@ -3557,7 +3553,7 @@ impl<'a> Parser<'a> { /// Parse a structure field fn parse_name_and_ty(&mut self, pr: Visibility, - attrs: Vec ) -> PResult { + attrs: Vec ) -> PResult<'a, StructField> { let lo = match pr { Inherited => self.span.lo, Public => self.last_span.lo, @@ -3589,11 +3585,11 @@ impl<'a> Parser<'a> { } /// Parse a statement. may include decl. - pub fn parse_stmt(&mut self) -> PResult>> { + pub fn parse_stmt(&mut self) -> PResult<'a, Option>> { Ok(try!(self.parse_stmt_()).map(P)) } - fn parse_stmt_(&mut self) -> PResult> { + fn parse_stmt_(&mut self) -> PResult<'a, Option> { maybe_whole!(Some deref self, NtStmt); let attrs = try!(self.parse_outer_attributes()); @@ -3729,7 +3725,7 @@ impl<'a> Parser<'a> { } /// Parse a block. No inner attrs are allowed. - pub fn parse_block(&mut self) -> PResult> { + pub fn parse_block(&mut self) -> PResult<'a, P> { maybe_whole!(no_clone self, NtBlock); let lo = self.span.lo; @@ -3746,7 +3742,7 @@ impl<'a> Parser<'a> { } /// Parse a block. Inner attrs are allowed. - fn parse_inner_attrs_and_block(&mut self) -> PResult<(Vec, P)> { + fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (Vec, P)> { maybe_whole!(pair_empty self, NtBlock); let lo = self.span.lo; @@ -3757,7 +3753,7 @@ impl<'a> Parser<'a> { /// Parse the rest of a block expression or function body /// Precondition: already parsed the '{'. - fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> PResult> { + fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> PResult<'a, P> { let mut stmts = vec![]; let mut expr = None; @@ -3851,7 +3847,7 @@ impl<'a> Parser<'a> { e: P, span: Span, stmts: &mut Vec>, - last_block_expr: &mut Option>) -> PResult<()> { + last_block_expr: &mut Option>) -> PResult<'a, ()> { // expression without semicolon if classify::expr_requires_semi_to_be_stmt(&*e) { // Just check for errors and recover; do not eat semicolon yet. @@ -3887,7 +3883,7 @@ impl<'a> Parser<'a> { // otherwise returns empty list. fn parse_colon_then_ty_param_bounds(&mut self, mode: BoundParsingMode) - -> PResult + -> PResult<'a, TyParamBounds> { if !try!(self.eat(&token::Colon) ){ Ok(P::empty()) @@ -3902,7 +3898,7 @@ impl<'a> Parser<'a> { // and bound = 'region | trait_ref fn parse_ty_param_bounds(&mut self, mode: BoundParsingMode) - -> PResult + -> PResult<'a, TyParamBounds> { let mut result = vec!(); loop { @@ -3948,7 +3944,7 @@ impl<'a> Parser<'a> { } /// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )? - fn parse_ty_param(&mut self) -> PResult { + fn parse_ty_param(&mut self) -> PResult<'a, TyParam> { let span = self.span; let ident = try!(self.parse_ident()); @@ -3977,7 +3973,7 @@ impl<'a> Parser<'a> { /// matches generics = ( ) | ( < > ) | ( < typaramseq ( , )? > ) | ( < lifetimes ( , )? > ) /// | ( < lifetimes , typaramseq ( , )? > ) /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) - pub fn parse_generics(&mut self) -> PResult { + pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { maybe_whole!(self, NtGenerics); if try!(self.eat(&token::Lt) ){ @@ -4008,7 +4004,7 @@ impl<'a> Parser<'a> { } } - fn parse_generic_values_after_lt(&mut self) -> PResult<(Vec, + fn parse_generic_values_after_lt(&mut self) -> PResult<'a, (Vec, Vec>, Vec>)> { let span_lo = self.span.lo; @@ -4025,7 +4021,7 @@ impl<'a> Parser<'a> { let msg = format!("expected `,` or `>` after lifetime \ name, found `{}`", self.this_token_to_string()); - self.span_err(self.span, &msg); + let mut err = self.diagnostic().struct_span_err(self.span, &msg); let span_hi = self.span.hi; let span_hi = if self.parse_ty().is_ok() { @@ -4037,7 +4033,8 @@ impl<'a> Parser<'a> { let msg = format!("did you mean a single argument type &'a Type, \ or did you mean the comma-separated arguments \ 'a, Type?"); - self.span_note(mk_sp(span_lo, span_hi), &msg); + err.span_note(mk_sp(span_lo, span_hi), &msg); + err.emit(); self.abort_if_errors() } @@ -4085,7 +4082,7 @@ impl<'a> Parser<'a> { Ok((lifetimes, types.into_vec(), bindings.into_vec())) } - fn forbid_lifetime(&mut self) -> PResult<()> { + fn forbid_lifetime(&mut self) -> PResult<'a, ()> { if self.token.is_lifetime() { let span = self.span; return Err(self.span_fatal(span, "lifetime parameters must be declared \ @@ -4099,7 +4096,7 @@ impl<'a> Parser<'a> { /// ```ignore /// where T : Trait + 'b, 'a : 'b /// ``` - pub fn parse_where_clause(&mut self) -> PResult { + pub fn parse_where_clause(&mut self) -> PResult<'a, ast::WhereClause> { maybe_whole!(self, NtWhereClause); let mut where_clause = WhereClause { @@ -4215,7 +4212,7 @@ impl<'a> Parser<'a> { } fn parse_fn_args(&mut self, named_args: bool, allow_variadic: bool) - -> PResult<(Vec , bool)> { + -> PResult<'a, (Vec , bool)> { let sp = self.span; let mut args: Vec> = try!(self.parse_unspanned_seq( @@ -4264,7 +4261,7 @@ impl<'a> Parser<'a> { } /// Parse the argument list and result type of a function declaration - pub fn parse_fn_decl(&mut self, allow_variadic: bool) -> PResult> { + pub fn parse_fn_decl(&mut self, allow_variadic: bool) -> PResult<'a, P> { let (args, variadic) = try!(self.parse_fn_args(true, allow_variadic)); let ret_ty = try!(self.parse_ret_ty()); @@ -4283,7 +4280,7 @@ impl<'a> Parser<'a> { } } - fn expect_self_ident(&mut self) -> PResult { + fn expect_self_ident(&mut self) -> PResult<'a, ast::Ident> { match self.token { token::Ident(id, token::Plain) if id.name == special_idents::self_.name => { try!(self.bump()); @@ -4304,7 +4301,7 @@ impl<'a> Parser<'a> { } } - fn expect_self_type_ident(&mut self) -> PResult { + fn expect_self_type_ident(&mut self) -> PResult<'a, ast::Ident> { match self.token { token::Ident(id, token::Plain) if id.name == special_idents::type_self.name => { try!(self.bump()); @@ -4321,11 +4318,11 @@ impl<'a> Parser<'a> { /// Parse the argument list and result type of a function /// that may have a self type. fn parse_fn_decl_with_self(&mut self, - parse_arg_fn: F) -> PResult<(ExplicitSelf, P)> where - F: FnMut(&mut Parser) -> PResult, + parse_arg_fn: F) -> PResult<'a, (ExplicitSelf, P)> where + F: FnMut(&mut Parser<'a>) -> PResult<'a, Arg>, { - fn maybe_parse_borrowed_explicit_self(this: &mut Parser) - -> PResult { + fn maybe_parse_borrowed_explicit_self<'b>(this: &mut Parser<'b>) + -> PResult<'b, ast::ExplicitSelf_> { // The following things are possible to see here: // // fn(&mut self) @@ -4483,7 +4480,7 @@ impl<'a> Parser<'a> { } // parse the |arg, arg| header on a lambda - fn parse_fn_block_decl(&mut self) -> PResult> { + fn parse_fn_block_decl(&mut self) -> PResult<'a, P> { let inputs_captures = { if try!(self.eat(&token::OrOr) ){ Vec::new() @@ -4509,7 +4506,7 @@ impl<'a> Parser<'a> { } /// Parse the name and optional generic types of a function header. - fn parse_fn_header(&mut self) -> PResult<(Ident, ast::Generics)> { + fn parse_fn_header(&mut self) -> PResult<'a, (Ident, ast::Generics)> { let id = try!(self.parse_ident()); let generics = try!(self.parse_generics()); Ok((id, generics)) @@ -4533,7 +4530,7 @@ impl<'a> Parser<'a> { unsafety: Unsafety, constness: Constness, abi: abi::Abi) - -> PResult { + -> PResult<'a, ItemInfo> { let (ident, mut generics) = try!(self.parse_fn_header()); let decl = try!(self.parse_fn_decl(false)); generics.where_clause = try!(self.parse_where_clause()); @@ -4556,7 +4553,8 @@ impl<'a> Parser<'a> { /// - `const unsafe fn` /// - `extern fn` /// - etc - pub fn parse_fn_front_matter(&mut self) -> PResult<(ast::Constness, ast::Unsafety, abi::Abi)> { + pub fn parse_fn_front_matter(&mut self) + -> PResult<'a, (ast::Constness, ast::Unsafety, abi::Abi)> { let is_const_fn = try!(self.eat_keyword(keywords::Const)); let unsafety = try!(self.parse_unsafety()); let (constness, unsafety, abi) = if is_const_fn { @@ -4574,7 +4572,7 @@ impl<'a> Parser<'a> { } /// Parse an impl item. - pub fn parse_impl_item(&mut self) -> PResult> { + pub fn parse_impl_item(&mut self) -> PResult<'a, P> { maybe_whole!(no_clone self, NtImplItem); let mut attrs = try!(self.parse_outer_attributes()); @@ -4614,9 +4612,10 @@ impl<'a> Parser<'a> { fn complain_if_pub_macro(&mut self, visa: Visibility, span: Span) { match visa { Public => { - self.span_err(span, "can't qualify macro invocation with `pub`"); - self.fileline_help(span, "try adjusting the macro to put `pub` inside \ - the invocation"); + self.diagnostic().struct_span_err(span, "can't qualify macro invocation with `pub`") + .fileline_help(span, "try adjusting the macro to put `pub` inside \ + the invocation") + .emit(); } Inherited => (), } @@ -4624,7 +4623,7 @@ impl<'a> Parser<'a> { /// Parse a method or a macro invocation in a trait impl. fn parse_impl_method(&mut self, vis: Visibility) - -> PResult<(Ident, Vec, ast::ImplItemKind)> { + -> PResult<'a, (Ident, Vec, ast::ImplItemKind)> { // code copied from parse_macro_use_or_failure... abstraction! if !self.token.is_any_keyword() && self.look_ahead(1, |t| *t == token::Not) @@ -4673,7 +4672,7 @@ impl<'a> Parser<'a> { } /// Parse trait Foo { ... } - fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult { + fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> { let ident = try!(self.parse_ident()); let mut tps = try!(self.parse_generics()); @@ -4691,7 +4690,7 @@ impl<'a> Parser<'a> { /// impl Foo { ... } /// impl ToString for &'static T { ... } /// impl Send for .. {} - fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> PResult { + fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> PResult<'a, ItemInfo> { let impl_span = self.span; // First, parse type parameters if necessary. @@ -4769,14 +4768,14 @@ impl<'a> Parser<'a> { } /// Parse a::B - fn parse_trait_ref(&mut self) -> PResult { + fn parse_trait_ref(&mut self) -> PResult<'a, TraitRef> { Ok(ast::TraitRef { path: try!(self.parse_path(LifetimeAndTypesWithoutColons)), ref_id: ast::DUMMY_NODE_ID, }) } - fn parse_late_bound_lifetime_defs(&mut self) -> PResult> { + fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { if try!(self.eat_keyword(keywords::For) ){ try!(self.expect(&token::Lt)); let lifetime_defs = try!(self.parse_lifetime_defs()); @@ -4788,7 +4787,7 @@ impl<'a> Parser<'a> { } /// Parse for<'l> a::B - fn parse_poly_trait_ref(&mut self) -> PResult { + fn parse_poly_trait_ref(&mut self) -> PResult<'a, PolyTraitRef> { let lo = self.span.lo; let lifetime_defs = try!(self.parse_late_bound_lifetime_defs()); @@ -4800,7 +4799,7 @@ impl<'a> Parser<'a> { } /// Parse struct Foo { ... } - fn parse_item_struct(&mut self) -> PResult { + fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { let class_name = try!(self.parse_ident()); let mut generics = try!(self.parse_generics()); @@ -4851,7 +4850,9 @@ impl<'a> Parser<'a> { Ok((class_name, ItemStruct(vdata, generics), None)) } - pub fn parse_record_struct_body(&mut self, parse_pub: ParsePub) -> PResult> { + pub fn parse_record_struct_body(&mut self, + parse_pub: ParsePub) + -> PResult<'a, Vec> { let mut fields = Vec::new(); if try!(self.eat(&token::OpenDelim(token::Brace)) ){ while self.token != token::CloseDelim(token::Brace) { @@ -4869,7 +4870,9 @@ impl<'a> Parser<'a> { Ok(fields) } - pub fn parse_tuple_struct_body(&mut self, parse_pub: ParsePub) -> PResult> { + pub fn parse_tuple_struct_body(&mut self, + parse_pub: ParsePub) + -> PResult<'a, Vec> { // This is the case where we find `struct Foo(T) where T: Copy;` // Unit like structs are handled in parse_item_struct function let fields = try!(self.parse_unspanned_seq( @@ -4901,7 +4904,7 @@ impl<'a> Parser<'a> { pub fn parse_single_struct_field(&mut self, vis: Visibility, attrs: Vec ) - -> PResult { + -> PResult<'a, StructField> { let a_var = try!(self.parse_name_and_ty(vis, attrs)); match self.token { token::Comma => { @@ -4921,7 +4924,7 @@ impl<'a> Parser<'a> { } /// Parse an element of a struct definition - fn parse_struct_decl_field(&mut self, parse_pub: ParsePub) -> PResult { + fn parse_struct_decl_field(&mut self, parse_pub: ParsePub) -> PResult<'a, StructField> { let attrs = try!(self.parse_outer_attributes()); @@ -4937,13 +4940,13 @@ impl<'a> Parser<'a> { } /// Parse visibility: PUB or nothing - fn parse_visibility(&mut self) -> PResult { + fn parse_visibility(&mut self) -> PResult<'a, Visibility> { if try!(self.eat_keyword(keywords::Pub)) { Ok(Public) } else { Ok(Inherited) } } /// Given a termination token, parse all of the items in a module - fn parse_mod_items(&mut self, term: &token::Token, inner_lo: BytePos) -> PResult { + fn parse_mod_items(&mut self, term: &token::Token, inner_lo: BytePos) -> PResult<'a, Mod> { let mut items = vec![]; while let Some(item) = try!(self.parse_item()) { items.push(item); @@ -4966,7 +4969,7 @@ impl<'a> Parser<'a> { }) } - fn parse_item_const(&mut self, m: Option) -> PResult { + fn parse_item_const(&mut self, m: Option) -> PResult<'a, ItemInfo> { let id = try!(self.parse_ident()); try!(self.expect(&token::Colon)); let ty = try!(self.parse_ty_sum()); @@ -4981,7 +4984,7 @@ impl<'a> Parser<'a> { } /// Parse a `mod { ... }` or `mod ;` item - fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult { + fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo> { let id_span = self.span; let id = try!(self.parse_ident()); if self.check(&token::Semi) { @@ -5060,7 +5063,7 @@ impl<'a> Parser<'a> { fn submod_path(&mut self, id: ast::Ident, outer_attrs: &[ast::Attribute], - id_sp: Span) -> PResult { + id_sp: Span) -> PResult<'a, ModulePathSuccess> { let mut prefix = PathBuf::from(&self.sess.codemap().span_to_filename(self.span)); prefix.pop(); let mut dir_path = prefix; @@ -5075,21 +5078,23 @@ impl<'a> Parser<'a> { let paths = Parser::default_submod_path(id, &dir_path, self.sess.codemap()); if !self.owns_directory { - self.span_err(id_sp, "cannot declare a new module at this location"); + let mut err = self.diagnostic().struct_span_err(id_sp, + "cannot declare a new module at this location"); let this_module = match self.mod_path_stack.last() { Some(name) => name.to_string(), None => self.root_module_name.as_ref().unwrap().clone(), }; - self.span_note(id_sp, - &format!("maybe move this module `{0}` to its own directory \ + err.span_note(id_sp, + &format!("maybe move this module `{0}` to its own directory \ via `{0}/mod.rs`", this_module)); if paths.path_exists { - self.span_note(id_sp, - &format!("... or maybe `use` the module `{}` instead \ - of possibly redeclaring it", - paths.name)); + err.span_note(id_sp, + &format!("... or maybe `use` the module `{}` instead \ + of possibly redeclaring it", + paths.name)); } + err.emit(); self.abort_if_errors(); } @@ -5104,7 +5109,7 @@ impl<'a> Parser<'a> { id: ast::Ident, outer_attrs: &[ast::Attribute], id_sp: Span) - -> PResult<(ast::Item_, Vec )> { + -> PResult<'a, (ast::Item_, Vec )> { let ModulePathSuccess { path, owns_directory } = try!(self.submod_path(id, outer_attrs, id_sp)); @@ -5119,7 +5124,7 @@ impl<'a> Parser<'a> { path: PathBuf, owns_directory: bool, name: String, - id_sp: Span) -> PResult<(ast::Item_, Vec )> { + id_sp: Span) -> PResult<'a, (ast::Item_, Vec )> { let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut(); match included_mod_stack.iter().position(|p| *p == path) { Some(i) => { @@ -5152,7 +5157,7 @@ impl<'a> Parser<'a> { /// Parse a function declaration from a foreign module fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, lo: BytePos, - attrs: Vec) -> PResult> { + attrs: Vec) -> PResult<'a, P> { try!(self.expect_keyword(keywords::Fn)); let (ident, mut generics) = try!(self.parse_fn_header()); @@ -5172,7 +5177,7 @@ impl<'a> Parser<'a> { /// Parse a static item from a foreign module fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: BytePos, - attrs: Vec) -> PResult> { + attrs: Vec) -> PResult<'a, P> { try!(self.expect_keyword(keywords::Static)); let mutbl = try!(self.eat_keyword(keywords::Mut)); @@ -5201,7 +5206,7 @@ impl<'a> Parser<'a> { lo: BytePos, visibility: Visibility, attrs: Vec) - -> PResult> { + -> PResult<'a, P> { let crate_name = try!(self.parse_ident()); let (maybe_path, ident) = if let Some(ident) = try!(self.parse_rename()) { @@ -5242,7 +5247,7 @@ impl<'a> Parser<'a> { opt_abi: Option, visibility: Visibility, mut attrs: Vec) - -> PResult> { + -> PResult<'a, P> { try!(self.expect(&token::OpenDelim(token::Brace))); let abi = opt_abi.unwrap_or(abi::C); @@ -5269,7 +5274,7 @@ impl<'a> Parser<'a> { } /// Parse type Foo = Bar; - fn parse_item_type(&mut self) -> PResult { + fn parse_item_type(&mut self) -> PResult<'a, ItemInfo> { let ident = try!(self.parse_ident()); let mut tps = try!(self.parse_generics()); tps.where_clause = try!(self.parse_where_clause()); @@ -5280,7 +5285,7 @@ impl<'a> Parser<'a> { } /// Parse the part of an "enum" decl following the '{' - fn parse_enum_def(&mut self, _generics: &ast::Generics) -> PResult { + fn parse_enum_def(&mut self, _generics: &ast::Generics) -> PResult<'a, EnumDef> { let mut variants = Vec::new(); let mut all_nullary = true; let mut any_disr = None; @@ -5330,7 +5335,7 @@ impl<'a> Parser<'a> { } /// Parse an "enum" declaration - fn parse_item_enum(&mut self) -> PResult { + fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> { let id = try!(self.parse_ident()); let mut generics = try!(self.parse_generics()); generics.where_clause = try!(self.parse_where_clause()); @@ -5342,7 +5347,7 @@ impl<'a> Parser<'a> { /// Parses a string as an ABI spec on an extern type or module. Consumes /// the `extern` keyword, if one is found. - fn parse_opt_abi(&mut self) -> PResult> { + fn parse_opt_abi(&mut self) -> PResult<'a, Option> { match self.token { token::Literal(token::Str_(s), suf) | token::Literal(token::StrRaw(s, _), suf) => { let sp = self.span; @@ -5371,7 +5376,7 @@ impl<'a> Parser<'a> { /// NB: this function no longer parses the items inside an /// extern crate. fn parse_item_(&mut self, attrs: Vec, - macros_allowed: bool, attributes_allowed: bool) -> PResult>> { + macros_allowed: bool, attributes_allowed: bool) -> PResult<'a, Option>> { let nt_item = match self.token { token::Interpolated(token::NtItem(ref item)) => { Some((**item).clone()) @@ -5474,8 +5479,9 @@ impl<'a> Parser<'a> { // CONST ITEM if try!(self.eat_keyword(keywords::Mut) ){ let last_span = self.last_span; - self.span_err(last_span, "const globals cannot be mutable"); - self.fileline_help(last_span, "did you mean to declare a static?"); + self.diagnostic().struct_span_err(last_span, "const globals cannot be mutable") + .fileline_help(last_span, "did you mean to declare a static?") + .emit(); } let (ident, item_, extra_attrs) = try!(self.parse_item_const(None)); let last_span = self.last_span; @@ -5633,7 +5639,7 @@ impl<'a> Parser<'a> { } /// Parse a foreign item. - fn parse_foreign_item(&mut self) -> PResult>> { + fn parse_foreign_item(&mut self) -> PResult<'a, Option>> { let attrs = try!(self.parse_outer_attributes()); let lo = self.span.lo; let visibility = try!(self.parse_visibility()); @@ -5664,7 +5670,7 @@ impl<'a> Parser<'a> { attributes_allowed: bool, lo: BytePos, visibility: Visibility - ) -> PResult>> { + ) -> PResult<'a, Option>> { if macros_allowed && !self.token.is_any_keyword() && self.look_ahead(1, |t| *t == token::Not) && (self.look_ahead(2, |t| t.is_plain_ident()) @@ -5736,7 +5742,7 @@ impl<'a> Parser<'a> { Ok(None) } - pub fn parse_item(&mut self) -> PResult>> { + pub fn parse_item(&mut self) -> PResult<'a, Option>> { let attrs = try!(self.parse_outer_attributes()); self.parse_item_(attrs, true, false) } @@ -5747,7 +5753,7 @@ impl<'a> Parser<'a> { /// | MOD? non_global_path MOD_SEP LBRACE ident_seq RBRACE /// | MOD? non_global_path MOD_SEP STAR /// | MOD? non_global_path - fn parse_view_path(&mut self) -> PResult> { + fn parse_view_path(&mut self) -> PResult<'a, P> { let lo = self.span.lo; // Allow a leading :: because the paths are absolute either way. @@ -5843,7 +5849,7 @@ impl<'a> Parser<'a> { Ok(P(spanned(lo, self.last_span.hi, ViewPathSimple(rename_to, path)))) } - fn parse_rename(&mut self) -> PResult> { + fn parse_rename(&mut self) -> PResult<'a, Option> { if try!(self.eat_keyword(keywords::As)) { self.parse_ident().map(Some) } else { @@ -5853,7 +5859,7 @@ impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main /// entry point for the parser. - pub fn parse_crate_mod(&mut self) -> PResult { + pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> { let lo = self.span.lo; Ok(ast::Crate { attrs: try!(self.parse_inner_attributes()), @@ -5865,7 +5871,7 @@ impl<'a> Parser<'a> { } pub fn parse_optional_str(&mut self) - -> PResult PResult<'a, Option<(InternedString, ast::StrStyle, Option)>> { let ret = match self.token { @@ -5881,7 +5887,7 @@ impl<'a> Parser<'a> { Ok(Some(ret)) } - pub fn parse_str(&mut self) -> PResult<(InternedString, StrStyle)> { + pub fn parse_str(&mut self) -> PResult<'a, (InternedString, StrStyle)> { match try!(self.parse_optional_str()) { Some((s, style, suf)) => { let sp = self.last_span; diff --git a/src/libsyntax/show_span.rs b/src/libsyntax/show_span.rs index 014c7b2a68f4f..5e3cd0773aa45 100644 --- a/src/libsyntax/show_span.rs +++ b/src/libsyntax/show_span.rs @@ -47,21 +47,21 @@ struct ShowSpanVisitor<'a> { impl<'a, 'v> Visitor<'v> for ShowSpanVisitor<'a> { fn visit_expr(&mut self, e: &ast::Expr) { if let Mode::Expression = self.mode { - self.span_diagnostic.span_note(e.span, "expression"); + self.span_diagnostic.span_warn(e.span, "expression"); } visit::walk_expr(self, e); } fn visit_pat(&mut self, p: &ast::Pat) { if let Mode::Pattern = self.mode { - self.span_diagnostic.span_note(p.span, "pattern"); + self.span_diagnostic.span_warn(p.span, "pattern"); } visit::walk_pat(self, p); } fn visit_ty(&mut self, t: &ast::Ty) { if let Mode::Type = self.mode { - self.span_diagnostic.span_note(t.span, "type"); + self.span_diagnostic.span_warn(t.span, "type"); } visit::walk_ty(self, t); } diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs index a462dbeb6e4ed..454b925a4945e 100644 --- a/src/libsyntax/util/parser_testing.rs +++ b/src/libsyntax/util/parser_testing.rs @@ -30,10 +30,9 @@ pub fn string_to_parser<'a>(ps: &'a ParseSess, source_str: String) -> Parser<'a> source_str) } -fn with_error_checking_parse(s: String, f: F) -> T where - F: FnOnce(&mut Parser) -> PResult, +fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> T where + F: FnOnce(&mut Parser<'a>) -> PResult<'a, T>, { - let ps = ParseSess::new(); let mut p = string_to_parser(&ps, s); let x = panictry!(f(&mut p)); p.abort_if_errors(); @@ -42,28 +41,32 @@ fn with_error_checking_parse(s: String, f: F) -> T where /// Parse a string, return a crate. pub fn string_to_crate (source_str : String) -> ast::Crate { - with_error_checking_parse(source_str, |p| { + let ps = ParseSess::new(); + with_error_checking_parse(source_str, &ps, |p| { p.parse_crate_mod() }) } /// Parse a string, return an expr pub fn string_to_expr (source_str : String) -> P { - with_error_checking_parse(source_str, |p| { + let ps = ParseSess::new(); + with_error_checking_parse(source_str, &ps, |p| { p.parse_expr() }) } /// Parse a string, return an item pub fn string_to_item (source_str : String) -> Option> { - with_error_checking_parse(source_str, |p| { + let ps = ParseSess::new(); + with_error_checking_parse(source_str, &ps, |p| { p.parse_item() }) } /// Parse a string, return a stmt pub fn string_to_stmt(source_str : String) -> Option> { - with_error_checking_parse(source_str, |p| { + let ps = ParseSess::new(); + with_error_checking_parse(source_str, &ps, |p| { p.parse_stmt() }) } @@ -71,7 +74,8 @@ pub fn string_to_stmt(source_str : String) -> Option> { /// Parse a string, return a pat. Uses "irrefutable"... which doesn't /// (currently) affect parsing. pub fn string_to_pat(source_str: String) -> P { - with_error_checking_parse(source_str, |p| { + let ps = ParseSess::new(); + with_error_checking_parse(source_str, &ps, |p| { p.parse_pat() }) } diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 24094f797e6c2..78e7f7462f317 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -130,10 +130,11 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) match names.get(name) { None => {} Some(prev) => { - ecx.span_err(e.span, - &format!("duplicate argument named `{}`", - name)); - ecx.parse_sess.span_diagnostic.span_note(prev.span, "previously here"); + ecx.struct_span_err(e.span, + &format!("duplicate argument named `{}`", + name)) + .span_note(prev.span, "previously here") + .emit(); continue } } diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index a032666595ebe..0f049fa979255 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -24,26 +24,13 @@ #![feature(str_char)] extern crate fmt_macros; +#[macro_use] extern crate syntax; use syntax::ext::base::{MacroExpanderFn, NormalTT}; use syntax::ext::base::{SyntaxEnv, SyntaxExtension}; use syntax::parse::token::intern; -// A variant of 'try!' that panics on Err(FatalError). This is used as a -// crutch on the way towards a non-panic!-prone parser. It should be used -// for fatal parsing errors; eventually we plan to convert all code using -// panictry to just use normal try -macro_rules! panictry { - ($e:expr) => ({ - use std::result::Result::{Ok, Err}; - use syntax::errors::FatalError; - match $e { - Ok(e) => e, - Err(FatalError) => panic!(FatalError) - } - }) -} mod asm; mod cfg; diff --git a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs index 7c1a45d020b22..b64e5778d9033 100644 --- a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs +++ b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs @@ -37,34 +37,36 @@ pub fn string_to_parser<'a>(ps: &'a ParseSess, source_str: String) -> Parser<'a> source_str) } -fn with_error_checking_parse(s: String, f: F) -> PResult where - F: FnOnce(&mut Parser) -> PResult, +fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> PResult<'a, T> where + F: FnOnce(&mut Parser<'a>) -> PResult<'a, T>, { - let ps = ParseSess::new(); let mut p = string_to_parser(&ps, s); let x = f(&mut p); if ps.span_diagnostic.has_errors() || p.token != token::Eof { + if let Err(mut e) = x { + e.cancel(); + } return Err(p.fatal("parse error")); } x } -fn expr(s: &str) -> PResult> { - with_error_checking_parse(s.to_string(), |p| { +fn expr<'a>(s: &str, ps: &'a ParseSess) -> PResult<'a, P> { + with_error_checking_parse(s.to_string(), ps, |p| { p.parse_expr() }) } -fn stmt(s: &str) -> PResult> { - with_error_checking_parse(s.to_string(), |p| { +fn stmt<'a>(s: &str, ps: &'a ParseSess) -> PResult<'a, P> { + with_error_checking_parse(s.to_string(), ps, |p| { p.parse_stmt().map(|s| s.unwrap()) }) } -fn attr(s: &str) -> PResult { - with_error_checking_parse(s.to_string(), |p| { +fn attr<'a>(s: &str, ps: &'a ParseSess) -> PResult<'a, ast::Attribute> { + with_error_checking_parse(s.to_string(), ps, |p| { p.parse_attribute(true) }) } @@ -79,29 +81,39 @@ fn str_compare String>(e: &str, expected: &[T], actual: &[T], f: } fn check_expr_attrs(es: &str, expected: &[&str]) { - let e = expr(es).expect("parse error"); + let ps = ParseSess::new(); + let e = expr(es, &ps).expect("parse error"); let actual = &e.attrs; str_compare(es, - &expected.iter().map(|r| attr(r).unwrap()).collect::>(), + &expected.iter().map(|r| attr(r, &ps).unwrap()).collect::>(), actual.as_attr_slice(), pprust::attribute_to_string); } fn check_stmt_attrs(es: &str, expected: &[&str]) { - let e = stmt(es).expect("parse error"); + let ps = ParseSess::new(); + let e = stmt(es, &ps).expect("parse error"); let actual = e.node.attrs(); str_compare(es, - &expected.iter().map(|r| attr(r).unwrap()).collect::>(), + &expected.iter().map(|r| attr(r, &ps).unwrap()).collect::>(), actual, pprust::attribute_to_string); } fn reject_expr_parse(es: &str) { - assert!(expr(es).is_err(), "parser did not reject `{}`", es); + let ps = ParseSess::new(); + match expr(es, &ps) { + Ok(_) => panic!("parser did not reject `{}`", es), + Err(mut e) => e.cancel(), + }; } fn reject_stmt_parse(es: &str) { - assert!(stmt(es).is_err(), "parser did not reject `{}`", es); + let ps = ParseSess::new(); + match stmt(es, &ps) { + Ok(_) => panic!("parser did not reject `{}`", es), + Err(mut e) => e.cancel(), + }; } fn main() {