diff options
Diffstat (limited to 'compiler/rustc_passes/src/loops.rs')
-rw-r--r-- | compiler/rustc_passes/src/loops.rs | 161 |
1 files changed, 45 insertions, 116 deletions
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index cdda0e388..077194ec6 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -1,6 +1,5 @@ use Context::*; -use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; @@ -13,6 +12,11 @@ use rustc_session::Session; use rustc_span::hygiene::DesugaringKind; use rustc_span::Span; +use crate::errors::{ + BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop, + UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock, +}; + #[derive(Clone, Copy, Debug, PartialEq)] enum Context { Normal, @@ -90,7 +94,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { Ok(loop_id) => Some(loop_id), Err(hir::LoopIdError::OutsideLoopScope) => None, Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => { - self.emit_unlabled_cf_in_while_condition(e.span, "break"); + self.sess.emit_err(UnlabeledCfInWhileCondition { + span: e.span, + cf_type: "break", + }); None } Err(hir::LoopIdError::UnresolvedLabel) => None, @@ -116,69 +123,22 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { match loop_kind { None | Some(hir::LoopSource::Loop) => (), Some(kind) => { - let mut err = struct_span_err!( - self.sess, - e.span, - E0571, - "`break` with value from a `{}` loop", - kind.name() - ); - err.span_label( - e.span, - "can only break with a value inside `loop` or breakable block", + let suggestion = format!( + "break{}", + break_label + .label + .map_or_else(String::new, |l| format!(" {}", l.ident)) ); - if let Some(head) = head { - err.span_label( - head, - &format!( - "you can't `break` with a value in a `{}` loop", - kind.name() - ), - ); - } - err.span_suggestion( - e.span, - &format!( - "use `break` on its own without a value inside this `{}` loop", - kind.name(), - ), - format!( - "break{}", - break_label - .label - .map_or_else(String::new, |l| format!(" {}", l.ident)) - ), - Applicability::MaybeIncorrect, - ); - if let (Some(label), None) = (loop_label, break_label.label) { - match break_expr.kind { - hir::ExprKind::Path(hir::QPath::Resolved( - None, - hir::Path { - segments: [segment], - res: hir::def::Res::Err, - .. - }, - )) if label.ident.to_string() - == format!("'{}", segment.ident) => - { - // This error is redundant, we will have already emitted a - // suggestion to use the label when `segment` wasn't found - // (hence the `Res::Err` check). - err.delay_as_bug(); - } - _ => { - err.span_suggestion( - break_expr.span, - "alternatively, you might have meant to use the \ - available loop label", - label.ident, - Applicability::MaybeIncorrect, - ); - } - } - } - err.emit(); + self.sess.emit_err(BreakNonLoop { + span: e.span, + head, + kind: kind.name(), + suggestion, + loop_label, + break_label: break_label.label, + break_expr_kind: &break_expr.kind, + break_expr_span: break_expr.span, + }); } } } @@ -191,19 +151,17 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { match destination.target_id { Ok(loop_id) => { if let Node::Block(block) = self.hir_map.find(loop_id).unwrap() { - struct_span_err!( - self.sess, - e.span, - E0696, - "`continue` pointing to a labeled block" - ) - .span_label(e.span, "labeled blocks cannot be `continue`'d") - .span_label(block.span, "labeled block the `continue` points to") - .emit(); + self.sess.emit_err(ContinueLabeledBlock { + span: e.span, + block_span: block.span, + }); } } Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => { - self.emit_unlabled_cf_in_while_condition(e.span, "continue"); + self.sess.emit_err(UnlabeledCfInWhileCondition { + span: e.span, + cf_type: "continue", + }); } Err(_) => {} } @@ -226,21 +184,16 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { } fn require_break_cx(&self, name: &str, span: Span) { - let err_inside_of = |article, ty, closure_span| { - struct_span_err!(self.sess, span, E0267, "`{}` inside of {} {}", name, article, ty) - .span_label(span, format!("cannot `{}` inside of {} {}", name, article, ty)) - .span_label(closure_span, &format!("enclosing {}", ty)) - .emit(); - }; - match self.cx { LabeledBlock | Loop(_) => {} - Closure(closure_span) => err_inside_of("a", "closure", closure_span), - AsyncClosure(closure_span) => err_inside_of("an", "`async` block", closure_span), + Closure(closure_span) => { + self.sess.emit_err(BreakInsideClosure { span, closure_span, name }); + } + AsyncClosure(closure_span) => { + self.sess.emit_err(BreakInsideAsyncBlock { span, closure_span, name }); + } Normal | AnonConst => { - struct_span_err!(self.sess, span, E0268, "`{}` outside of a loop", name) - .span_label(span, format!("cannot `{}` outside of a loop", name)) - .emit(); + self.sess.emit_err(OutsideLoop { span, name }); } } } @@ -251,37 +204,13 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { label: &Destination, cf_type: &str, ) -> bool { - if !span.is_desugaring(DesugaringKind::QuestionMark) && self.cx == LabeledBlock { - if label.label.is_none() { - struct_span_err!( - self.sess, - span, - E0695, - "unlabeled `{}` inside of a labeled block", - cf_type - ) - .span_label( - span, - format!( - "`{}` statements that would diverge to or through \ - a labeled block need to bear a label", - cf_type - ), - ) - .emit(); - return true; - } + if !span.is_desugaring(DesugaringKind::QuestionMark) + && self.cx == LabeledBlock + && label.label.is_none() + { + self.sess.emit_err(UnlabeledInLabeledBlock { span, cf_type }); + return true; } false } - fn emit_unlabled_cf_in_while_condition(&mut self, span: Span, cf_type: &str) { - struct_span_err!( - self.sess, - span, - E0590, - "`break` or `continue` with no label in the condition of a `while` loop" - ) - .span_label(span, format!("unlabeled `{}` in the condition of a `while` loop", cf_type)) - .emit(); - } } |