Rollup merge of #81236 - estebank:everybody-loop-now, r=oli-obk
Gracefully handle loop labels missing leading `'` in different positions Fix #81192. * Account for labels when suggesting `loop` instead of `while true` * Suggest `'a` when given `a` only when appropriate * Add loop head span to hir * Tweak error for invalid `break expr` * Add more misspelled label tests * Avoid emitting redundant "unused label" lint * Parse loop labels missing a leading `'` Each commit can be reviewed in isolation.
This commit is contained in:
commit
3682a06dcf
33 changed files with 523 additions and 139 deletions
|
@ -10,9 +10,9 @@ use rustc_errors::struct_span_err;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::Res;
|
use rustc_hir::def::Res;
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_span::hygiene::ForLoopLoc;
|
|
||||||
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
|
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
|
||||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||||
|
use rustc_span::{hygiene::ForLoopLoc, DUMMY_SP};
|
||||||
use rustc_target::asm;
|
use rustc_target::asm;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
@ -102,6 +102,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
this.lower_block(body, false),
|
this.lower_block(body, false),
|
||||||
opt_label,
|
opt_label,
|
||||||
hir::LoopSource::Loop,
|
hir::LoopSource::Loop,
|
||||||
|
DUMMY_SP,
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body),
|
ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body),
|
||||||
|
@ -453,7 +454,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
self.expr_match(span, scrutinee, arena_vec![self; then_arm, else_arm], desugar);
|
self.expr_match(span, scrutinee, arena_vec![self; then_arm, else_arm], desugar);
|
||||||
|
|
||||||
// `[opt_ident]: loop { ... }`
|
// `[opt_ident]: loop { ... }`
|
||||||
hir::ExprKind::Loop(self.block_expr(self.arena.alloc(match_expr)), opt_label, source)
|
hir::ExprKind::Loop(
|
||||||
|
self.block_expr(self.arena.alloc(match_expr)),
|
||||||
|
opt_label,
|
||||||
|
source,
|
||||||
|
span.with_hi(cond.span.hi()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`,
|
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`,
|
||||||
|
@ -748,7 +754,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
// loop { .. }
|
// loop { .. }
|
||||||
let loop_expr = self.arena.alloc(hir::Expr {
|
let loop_expr = self.arena.alloc(hir::Expr {
|
||||||
hir_id: loop_hir_id,
|
hir_id: loop_hir_id,
|
||||||
kind: hir::ExprKind::Loop(loop_block, None, hir::LoopSource::Loop),
|
kind: hir::ExprKind::Loop(loop_block, None, hir::LoopSource::Loop, span),
|
||||||
span,
|
span,
|
||||||
attrs: ThinVec::new(),
|
attrs: ThinVec::new(),
|
||||||
});
|
});
|
||||||
|
@ -1709,7 +1715,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
);
|
);
|
||||||
|
|
||||||
// `[opt_ident]: loop { ... }`
|
// `[opt_ident]: loop { ... }`
|
||||||
let kind = hir::ExprKind::Loop(loop_block, opt_label, hir::LoopSource::ForLoop);
|
let kind = hir::ExprKind::Loop(
|
||||||
|
loop_block,
|
||||||
|
opt_label,
|
||||||
|
hir::LoopSource::ForLoop,
|
||||||
|
e.span.with_hi(orig_head_span.hi()),
|
||||||
|
);
|
||||||
let loop_expr = self.arena.alloc(hir::Expr {
|
let loop_expr = self.arena.alloc(hir::Expr {
|
||||||
hir_id: self.lower_node_id(e.id),
|
hir_id: self.lower_node_id(e.id),
|
||||||
kind,
|
kind,
|
||||||
|
|
|
@ -1617,7 +1617,9 @@ pub enum ExprKind<'hir> {
|
||||||
/// A conditionless loop (can be exited with `break`, `continue`, or `return`).
|
/// A conditionless loop (can be exited with `break`, `continue`, or `return`).
|
||||||
///
|
///
|
||||||
/// I.e., `'label: loop { <block> }`.
|
/// I.e., `'label: loop { <block> }`.
|
||||||
Loop(&'hir Block<'hir>, Option<Label>, LoopSource),
|
///
|
||||||
|
/// The `Span` is the loop header (`for x in y`/`while let pat = expr`).
|
||||||
|
Loop(&'hir Block<'hir>, Option<Label>, LoopSource, Span),
|
||||||
/// A `match` block, with a source that indicates whether or not it is
|
/// A `match` block, with a source that indicates whether or not it is
|
||||||
/// the result of a desugaring, and if so, which kind.
|
/// the result of a desugaring, and if so, which kind.
|
||||||
Match(&'hir Expr<'hir>, &'hir [Arm<'hir>], MatchSource),
|
Match(&'hir Expr<'hir>, &'hir [Arm<'hir>], MatchSource),
|
||||||
|
|
|
@ -1151,7 +1151,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
||||||
visitor.visit_expr(then);
|
visitor.visit_expr(then);
|
||||||
walk_list!(visitor, visit_expr, else_opt);
|
walk_list!(visitor, visit_expr, else_opt);
|
||||||
}
|
}
|
||||||
ExprKind::Loop(ref block, ref opt_label, _) => {
|
ExprKind::Loop(ref block, ref opt_label, _, _) => {
|
||||||
walk_list!(visitor, visit_label, opt_label);
|
walk_list!(visitor, visit_label, opt_label);
|
||||||
visitor.visit_block(block);
|
visitor.visit_block(block);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1396,7 +1396,7 @@ impl<'a> State<'a> {
|
||||||
hir::ExprKind::If(ref test, ref blk, ref elseopt) => {
|
hir::ExprKind::If(ref test, ref blk, ref elseopt) => {
|
||||||
self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e));
|
self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e));
|
||||||
}
|
}
|
||||||
hir::ExprKind::Loop(ref blk, opt_label, _) => {
|
hir::ExprKind::Loop(ref blk, opt_label, _, _) => {
|
||||||
if let Some(label) = opt_label {
|
if let Some(label) = opt_label {
|
||||||
self.print_ident(label.ident);
|
self.print_ident(label.ident);
|
||||||
self.word_space(":");
|
self.word_space(":");
|
||||||
|
|
|
@ -96,18 +96,24 @@ fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
|
||||||
|
|
||||||
impl EarlyLintPass for WhileTrue {
|
impl EarlyLintPass for WhileTrue {
|
||||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
||||||
if let ast::ExprKind::While(cond, ..) = &e.kind {
|
if let ast::ExprKind::While(cond, _, label) = &e.kind {
|
||||||
if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind {
|
if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind {
|
||||||
if let ast::LitKind::Bool(true) = lit.kind {
|
if let ast::LitKind::Bool(true) = lit.kind {
|
||||||
if !lit.span.from_expansion() {
|
if !lit.span.from_expansion() {
|
||||||
let msg = "denote infinite loops with `loop { ... }`";
|
let msg = "denote infinite loops with `loop { ... }`";
|
||||||
let condition_span = cx.sess.source_map().guess_head_span(e.span);
|
let condition_span = e.span.with_hi(cond.span.hi());
|
||||||
cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
|
cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
|
||||||
lint.build(msg)
|
lint.build(msg)
|
||||||
.span_suggestion_short(
|
.span_suggestion_short(
|
||||||
condition_span,
|
condition_span,
|
||||||
"use `loop`",
|
"use `loop`",
|
||||||
"loop".to_owned(),
|
format!(
|
||||||
|
"{}loop",
|
||||||
|
label.map_or_else(String::new, |label| format!(
|
||||||
|
"{}: ",
|
||||||
|
label.ident,
|
||||||
|
))
|
||||||
|
),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
|
|
|
@ -546,9 +546,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
|
||||||
scrutinee: discr.to_ref(),
|
scrutinee: discr.to_ref(),
|
||||||
arms: arms.iter().map(|a| convert_arm(cx, a)).collect(),
|
arms: arms.iter().map(|a| convert_arm(cx, a)).collect(),
|
||||||
},
|
},
|
||||||
hir::ExprKind::Loop(ref body, _, _) => {
|
hir::ExprKind::Loop(ref body, ..) => ExprKind::Loop { body: block::to_expr_ref(cx, body) },
|
||||||
ExprKind::Loop { body: block::to_expr_ref(cx, body) }
|
|
||||||
}
|
|
||||||
hir::ExprKind::Field(ref source, ..) => ExprKind::Field {
|
hir::ExprKind::Field(ref source, ..) => ExprKind::Field {
|
||||||
lhs: source.to_ref(),
|
lhs: source.to_ref(),
|
||||||
name: Field::new(cx.tcx.field_index(expr.hir_id, cx.typeck_results)),
|
name: Field::new(cx.tcx.field_index(expr.hir_id, cx.typeck_results)),
|
||||||
|
|
|
@ -585,7 +585,7 @@ impl<'a> Parser<'a> {
|
||||||
lhs_span: Span,
|
lhs_span: Span,
|
||||||
expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind,
|
expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind,
|
||||||
) -> PResult<'a, P<Expr>> {
|
) -> PResult<'a, P<Expr>> {
|
||||||
let mk_expr = |this: &mut Self, rhs: P<Ty>| {
|
let mk_expr = |this: &mut Self, lhs: P<Expr>, rhs: P<Ty>| {
|
||||||
this.mk_expr(
|
this.mk_expr(
|
||||||
this.mk_expr_sp(&lhs, lhs_span, rhs.span),
|
this.mk_expr_sp(&lhs, lhs_span, rhs.span),
|
||||||
expr_kind(lhs, rhs),
|
expr_kind(lhs, rhs),
|
||||||
|
@ -597,13 +597,49 @@ impl<'a> Parser<'a> {
|
||||||
// LessThan comparison after this cast.
|
// LessThan comparison after this cast.
|
||||||
let parser_snapshot_before_type = self.clone();
|
let parser_snapshot_before_type = self.clone();
|
||||||
let cast_expr = match self.parse_ty_no_plus() {
|
let cast_expr = match self.parse_ty_no_plus() {
|
||||||
Ok(rhs) => mk_expr(self, rhs),
|
Ok(rhs) => mk_expr(self, lhs, rhs),
|
||||||
Err(mut type_err) => {
|
Err(mut type_err) => {
|
||||||
// Rewind to before attempting to parse the type with generics, to recover
|
// Rewind to before attempting to parse the type with generics, to recover
|
||||||
// from situations like `x as usize < y` in which we first tried to parse
|
// from situations like `x as usize < y` in which we first tried to parse
|
||||||
// `usize < y` as a type with generic arguments.
|
// `usize < y` as a type with generic arguments.
|
||||||
let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);
|
let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);
|
||||||
|
|
||||||
|
// Check for typo of `'a: loop { break 'a }` with a missing `'`.
|
||||||
|
match (&lhs.kind, &self.token.kind) {
|
||||||
|
(
|
||||||
|
// `foo: `
|
||||||
|
ExprKind::Path(None, ast::Path { segments, .. }),
|
||||||
|
TokenKind::Ident(kw::For | kw::Loop | kw::While, false),
|
||||||
|
) if segments.len() == 1 => {
|
||||||
|
let snapshot = self.clone();
|
||||||
|
let label = Label {
|
||||||
|
ident: Ident::from_str_and_span(
|
||||||
|
&format!("'{}", segments[0].ident),
|
||||||
|
segments[0].ident.span,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
match self.parse_labeled_expr(label, AttrVec::new(), false) {
|
||||||
|
Ok(expr) => {
|
||||||
|
type_err.cancel();
|
||||||
|
self.struct_span_err(label.ident.span, "malformed loop label")
|
||||||
|
.span_suggestion(
|
||||||
|
label.ident.span,
|
||||||
|
"use the correct loop label format",
|
||||||
|
label.ident.to_string(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
return Ok(expr);
|
||||||
|
}
|
||||||
|
Err(mut err) => {
|
||||||
|
err.cancel();
|
||||||
|
*self = snapshot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
match self.parse_path(PathStyle::Expr) {
|
match self.parse_path(PathStyle::Expr) {
|
||||||
Ok(path) => {
|
Ok(path) => {
|
||||||
let (op_noun, op_verb) = match self.token.kind {
|
let (op_noun, op_verb) = match self.token.kind {
|
||||||
|
@ -630,7 +666,8 @@ impl<'a> Parser<'a> {
|
||||||
op_noun,
|
op_noun,
|
||||||
);
|
);
|
||||||
let span_after_type = parser_snapshot_after_type.token.span;
|
let span_after_type = parser_snapshot_after_type.token.span;
|
||||||
let expr = mk_expr(self, self.mk_ty(path.span, TyKind::Path(None, path)));
|
let expr =
|
||||||
|
mk_expr(self, lhs, self.mk_ty(path.span, TyKind::Path(None, path)));
|
||||||
|
|
||||||
let expr_str = self
|
let expr_str = self
|
||||||
.span_to_snippet(expr.span)
|
.span_to_snippet(expr.span)
|
||||||
|
@ -1067,7 +1104,7 @@ impl<'a> Parser<'a> {
|
||||||
} else if self.eat_keyword(kw::While) {
|
} else if self.eat_keyword(kw::While) {
|
||||||
self.parse_while_expr(None, self.prev_token.span, attrs)
|
self.parse_while_expr(None, self.prev_token.span, attrs)
|
||||||
} else if let Some(label) = self.eat_label() {
|
} else if let Some(label) = self.eat_label() {
|
||||||
self.parse_labeled_expr(label, attrs)
|
self.parse_labeled_expr(label, attrs, true)
|
||||||
} else if self.eat_keyword(kw::Loop) {
|
} else if self.eat_keyword(kw::Loop) {
|
||||||
self.parse_loop_expr(None, self.prev_token.span, attrs)
|
self.parse_loop_expr(None, self.prev_token.span, attrs)
|
||||||
} else if self.eat_keyword(kw::Continue) {
|
} else if self.eat_keyword(kw::Continue) {
|
||||||
|
@ -1228,7 +1265,12 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse `'label: $expr`. The label is already parsed.
|
/// Parse `'label: $expr`. The label is already parsed.
|
||||||
fn parse_labeled_expr(&mut self, label: Label, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
fn parse_labeled_expr(
|
||||||
|
&mut self,
|
||||||
|
label: Label,
|
||||||
|
attrs: AttrVec,
|
||||||
|
consume_colon: bool,
|
||||||
|
) -> PResult<'a, P<Expr>> {
|
||||||
let lo = label.ident.span;
|
let lo = label.ident.span;
|
||||||
let label = Some(label);
|
let label = Some(label);
|
||||||
let ate_colon = self.eat(&token::Colon);
|
let ate_colon = self.eat(&token::Colon);
|
||||||
|
@ -1247,7 +1289,7 @@ impl<'a> Parser<'a> {
|
||||||
self.parse_expr()
|
self.parse_expr()
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
if !ate_colon {
|
if !ate_colon && consume_colon {
|
||||||
self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span);
|
self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -199,7 +199,7 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
|
||||||
// Skip the following checks if we are not currently in a const context.
|
// Skip the following checks if we are not currently in a const context.
|
||||||
_ if self.const_kind.is_none() => {}
|
_ if self.const_kind.is_none() => {}
|
||||||
|
|
||||||
hir::ExprKind::Loop(_, _, source) => {
|
hir::ExprKind::Loop(_, _, source, _) => {
|
||||||
self.const_check_violated(NonConstExpr::Loop(*source), e.span);
|
self.const_check_violated(NonConstExpr::Loop(*source), e.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -844,7 +844,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
|
|
||||||
// Note that labels have been resolved, so we don't need to look
|
// Note that labels have been resolved, so we don't need to look
|
||||||
// at the label ident
|
// at the label ident
|
||||||
hir::ExprKind::Loop(ref blk, _, _) => self.propagate_through_loop(expr, &blk, succ),
|
hir::ExprKind::Loop(ref blk, ..) => self.propagate_through_loop(expr, &blk, succ),
|
||||||
|
|
||||||
hir::ExprKind::If(ref cond, ref then, ref else_opt) => {
|
hir::ExprKind::If(ref cond, ref then, ref else_opt) => {
|
||||||
//
|
//
|
||||||
|
|
|
@ -53,7 +53,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||||
|
|
||||||
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
||||||
match e.kind {
|
match e.kind {
|
||||||
hir::ExprKind::Loop(ref b, _, source) => {
|
hir::ExprKind::Loop(ref b, _, source, _) => {
|
||||||
self.with_context(Loop(source), |v| v.visit_block(&b));
|
self.with_context(Loop(source), |v| v.visit_block(&b));
|
||||||
}
|
}
|
||||||
hir::ExprKind::Closure(_, ref function_decl, b, span, movability) => {
|
hir::ExprKind::Closure(_, ref function_decl, b, span, movability) => {
|
||||||
|
@ -68,18 +68,18 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||||
hir::ExprKind::Block(ref b, Some(_label)) => {
|
hir::ExprKind::Block(ref b, Some(_label)) => {
|
||||||
self.with_context(LabeledBlock, |v| v.visit_block(&b));
|
self.with_context(LabeledBlock, |v| v.visit_block(&b));
|
||||||
}
|
}
|
||||||
hir::ExprKind::Break(label, ref opt_expr) => {
|
hir::ExprKind::Break(break_label, ref opt_expr) => {
|
||||||
if let Some(e) = opt_expr {
|
if let Some(e) = opt_expr {
|
||||||
self.visit_expr(e);
|
self.visit_expr(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.require_label_in_labeled_block(e.span, &label, "break") {
|
if self.require_label_in_labeled_block(e.span, &break_label, "break") {
|
||||||
// If we emitted an error about an unlabeled break in a labeled
|
// If we emitted an error about an unlabeled break in a labeled
|
||||||
// block, we don't need any further checking for this break any more
|
// block, we don't need any further checking for this break any more
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let loop_id = match label.target_id {
|
let loop_id = match break_label.target_id {
|
||||||
Ok(loop_id) => Some(loop_id),
|
Ok(loop_id) => Some(loop_id),
|
||||||
Err(hir::LoopIdError::OutsideLoopScope) => None,
|
Err(hir::LoopIdError::OutsideLoopScope) => None,
|
||||||
Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
|
Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
|
||||||
|
@ -89,49 +89,89 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||||
Err(hir::LoopIdError::UnresolvedLabel) => None,
|
Err(hir::LoopIdError::UnresolvedLabel) => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(loop_id) = loop_id {
|
if let Some(Node::Block(_)) = loop_id.and_then(|id| self.hir_map.find(id)) {
|
||||||
if let Node::Block(_) = self.hir_map.find(loop_id).unwrap() {
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if opt_expr.is_some() {
|
if let Some(break_expr) = opt_expr {
|
||||||
let loop_kind = if let Some(loop_id) = loop_id {
|
let (head, loop_label, loop_kind) = if let Some(loop_id) = loop_id {
|
||||||
Some(match self.hir_map.expect_expr(loop_id).kind {
|
match self.hir_map.expect_expr(loop_id).kind {
|
||||||
hir::ExprKind::Loop(_, _, source) => source,
|
hir::ExprKind::Loop(_, label, source, sp) => {
|
||||||
|
(Some(sp), label, Some(source))
|
||||||
|
}
|
||||||
ref r => {
|
ref r => {
|
||||||
span_bug!(e.span, "break label resolved to a non-loop: {:?}", r)
|
span_bug!(e.span, "break label resolved to a non-loop: {:?}", r)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
(None, None, None)
|
||||||
};
|
};
|
||||||
match loop_kind {
|
match loop_kind {
|
||||||
None | Some(hir::LoopSource::Loop) => (),
|
None | Some(hir::LoopSource::Loop) => (),
|
||||||
Some(kind) => {
|
Some(kind) => {
|
||||||
struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self.sess,
|
self.sess,
|
||||||
e.span,
|
e.span,
|
||||||
E0571,
|
E0571,
|
||||||
"`break` with value from a `{}` loop",
|
"`break` with value from a `{}` loop",
|
||||||
kind.name()
|
kind.name()
|
||||||
)
|
);
|
||||||
.span_label(
|
err.span_label(
|
||||||
e.span,
|
e.span,
|
||||||
"can only break with a value inside \
|
"can only break with a value inside `loop` or breakable block",
|
||||||
`loop` or breakable block",
|
);
|
||||||
)
|
if let Some(head) = head {
|
||||||
.span_suggestion(
|
err.span_label(
|
||||||
|
head,
|
||||||
|
&format!(
|
||||||
|
"you can't `break` with a value in a `{}` loop",
|
||||||
|
kind.name()
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
err.span_suggestion(
|
||||||
e.span,
|
e.span,
|
||||||
&format!(
|
&format!(
|
||||||
"instead, use `break` on its own \
|
"use `break` on its own without a value inside this `{}` loop",
|
||||||
without a value inside this `{}` loop",
|
kind.name(),
|
||||||
kind.name()
|
),
|
||||||
|
format!(
|
||||||
|
"break{}",
|
||||||
|
break_label
|
||||||
|
.label
|
||||||
|
.map_or_else(String::new, |l| format!(" {}", l.ident))
|
||||||
),
|
),
|
||||||
"break".to_string(),
|
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
)
|
);
|
||||||
.emit();
|
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.to_string(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,7 +252,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
|
||||||
terminating(then.hir_id.local_id);
|
terminating(then.hir_id.local_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::Loop(ref body, _, _) => {
|
hir::ExprKind::Loop(ref body, _, _, _) => {
|
||||||
terminating(body.hir_id.local_id);
|
terminating(body.hir_id.local_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2266,6 +2266,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
visit::walk_expr(self, expr);
|
visit::walk_expr(self, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExprKind::Break(None, Some(ref e)) => {
|
||||||
|
// We use this instead of `visit::walk_expr` to keep the parent expr around for
|
||||||
|
// better diagnostics.
|
||||||
|
self.resolve_expr(e, Some(&expr));
|
||||||
|
}
|
||||||
|
|
||||||
ExprKind::Let(ref pat, ref scrutinee) => {
|
ExprKind::Let(ref pat, ref scrutinee) => {
|
||||||
self.visit_expr(scrutinee);
|
self.visit_expr(scrutinee);
|
||||||
self.resolve_pattern_top(pat, PatternSource::Let);
|
self.resolve_pattern_top(pat, PatternSource::Let);
|
||||||
|
|
|
@ -545,17 +545,23 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
if let Some(err_code) = &err.code {
|
if let Some(err_code) = &err.code {
|
||||||
if err_code == &rustc_errors::error_code!(E0425) {
|
if err_code == &rustc_errors::error_code!(E0425) {
|
||||||
for label_rib in &self.label_ribs {
|
for label_rib in &self.label_ribs {
|
||||||
for (label_ident, _) in &label_rib.bindings {
|
for (label_ident, node_id) in &label_rib.bindings {
|
||||||
if format!("'{}", ident) == label_ident.to_string() {
|
if format!("'{}", ident) == label_ident.to_string() {
|
||||||
let msg = "a label with a similar name exists";
|
err.span_label(label_ident.span, "a label with a similar name exists");
|
||||||
// FIXME: consider only emitting this suggestion if a label would be valid here
|
if let PathSource::Expr(Some(Expr {
|
||||||
// which is pretty much only the case for `break` expressions.
|
kind: ExprKind::Break(None, Some(_)),
|
||||||
err.span_suggestion(
|
..
|
||||||
span,
|
})) = source
|
||||||
&msg,
|
{
|
||||||
label_ident.name.to_string(),
|
err.span_suggestion(
|
||||||
Applicability::MaybeIncorrect,
|
span,
|
||||||
);
|
"use the similarly named label",
|
||||||
|
label_ident.name.to_string(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
// Do not lint against unused label when we suggest them.
|
||||||
|
self.diagnostic_metadata.unused_labels.remove(node_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1173,7 +1173,7 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expression_label(ex: &hir::Expr<'_>) -> Option<Ident> {
|
fn expression_label(ex: &hir::Expr<'_>) -> Option<Ident> {
|
||||||
if let hir::ExprKind::Loop(_, Some(label), _) = ex.kind { Some(label.ident) } else { None }
|
if let hir::ExprKind::Loop(_, Some(label), ..) = ex.kind { Some(label.ident) } else { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_if_label_shadows_lifetime(tcx: TyCtxt<'_>, mut scope: ScopeRef<'_>, label: Ident) {
|
fn check_if_label_shadows_lifetime(tcx: TyCtxt<'_>, mut scope: ScopeRef<'_>, label: Ident) {
|
||||||
|
|
|
@ -266,7 +266,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
|
ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
|
||||||
ExprKind::Loop(ref body, _, source) => {
|
ExprKind::Loop(ref body, _, source, _) => {
|
||||||
self.check_expr_loop(body, source, expected, expr)
|
self.check_expr_loop(body, source, expected, expr)
|
||||||
}
|
}
|
||||||
ExprKind::Match(ref discrim, ref arms, match_src) => {
|
ExprKind::Match(ref discrim, ref arms, match_src) => {
|
||||||
|
|
|
@ -289,7 +289,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||||
| hir::ExprKind::ConstBlock(..)
|
| hir::ExprKind::ConstBlock(..)
|
||||||
| hir::ExprKind::Err => {}
|
| hir::ExprKind::Err => {}
|
||||||
|
|
||||||
hir::ExprKind::Loop(ref blk, _, _) => {
|
hir::ExprKind::Loop(ref blk, ..) => {
|
||||||
self.walk_block(blk);
|
self.walk_block(blk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
loop { //~ ERROR denote infinite loops with `loop
|
'a: loop { //~ ERROR denote infinite loops with `loop
|
||||||
i += 1;
|
i += 1;
|
||||||
if i == 5 { break; }
|
if i == 5 { break 'a; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while true { //~ ERROR denote infinite loops with `loop
|
'a: while true { //~ ERROR denote infinite loops with `loop
|
||||||
i += 1;
|
i += 1;
|
||||||
if i == 5 { break; }
|
if i == 5 { break 'a; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: denote infinite loops with `loop { ... }`
|
error: denote infinite loops with `loop { ... }`
|
||||||
--> $DIR/issue-1962.rs:6:5
|
--> $DIR/issue-1962.rs:6:5
|
||||||
|
|
|
|
||||||
LL | while true {
|
LL | 'a: while true {
|
||||||
| ^^^^^^^^^^ help: use `loop`
|
| ^^^^^^^^^^^^^^ help: use `loop`
|
||||||
|
|
|
|
||||||
= note: requested on the command line with `-D while-true`
|
= note: requested on the command line with `-D while-true`
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ warning: denote infinite loops with `loop { ... }`
|
||||||
LL | / 'b:
|
LL | / 'b:
|
||||||
LL | |
|
LL | |
|
||||||
LL | | while true { break }; // but here we cite the whole loop
|
LL | | while true { break }; // but here we cite the whole loop
|
||||||
| |____________________________^ help: use `loop`
|
| |__________________^ help: use `loop`
|
||||||
|
|
|
|
||||||
= note: `#[warn(while_true)]` on by default
|
= note: `#[warn(while_true)]` on by default
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,62 @@
|
||||||
|
#![warn(unused_labels)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
'LOOP: loop {
|
|
||||||
LOOP;
|
|
||||||
//~^ ERROR cannot find value `LOOP` in this scope
|
|
||||||
};
|
|
||||||
'while_loop: while true { //~ WARN denote infinite loops with
|
'while_loop: while true { //~ WARN denote infinite loops with
|
||||||
|
//~^ WARN unused label
|
||||||
while_loop;
|
while_loop;
|
||||||
//~^ ERROR cannot find value `while_loop` in this scope
|
//~^ ERROR cannot find value `while_loop` in this scope
|
||||||
};
|
};
|
||||||
'while_let: while let Some(_) = Some(()) {
|
'while_let: while let Some(_) = Some(()) {
|
||||||
|
//~^ WARN unused label
|
||||||
while_let;
|
while_let;
|
||||||
//~^ ERROR cannot find value `while_let` in this scope
|
//~^ ERROR cannot find value `while_let` in this scope
|
||||||
}
|
}
|
||||||
'for_loop: for _ in 0..3 {
|
'for_loop: for _ in 0..3 {
|
||||||
|
//~^ WARN unused label
|
||||||
for_loop;
|
for_loop;
|
||||||
//~^ ERROR cannot find value `for_loop` in this scope
|
//~^ ERROR cannot find value `for_loop` in this scope
|
||||||
};
|
};
|
||||||
|
'LOOP: loop {
|
||||||
|
//~^ WARN unused label
|
||||||
|
LOOP;
|
||||||
|
//~^ ERROR cannot find value `LOOP` in this scope
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
'LOOP: loop {
|
||||||
|
break LOOP;
|
||||||
|
//~^ ERROR cannot find value `LOOP` in this scope
|
||||||
|
};
|
||||||
|
'while_loop: while true { //~ WARN denote infinite loops with
|
||||||
|
break while_loop;
|
||||||
|
//~^ ERROR cannot find value `while_loop` in this scope
|
||||||
|
};
|
||||||
|
'while_let: while let Some(_) = Some(()) {
|
||||||
|
break while_let;
|
||||||
|
//~^ ERROR cannot find value `while_let` in this scope
|
||||||
|
}
|
||||||
|
'for_loop: for _ in 0..3 {
|
||||||
|
break for_loop;
|
||||||
|
//~^ ERROR cannot find value `for_loop` in this scope
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar() {
|
||||||
|
let foo = ();
|
||||||
|
'while_loop: while true { //~ WARN denote infinite loops with
|
||||||
|
//~^ WARN unused label
|
||||||
|
break foo;
|
||||||
|
//~^ ERROR `break` with value from a `while` loop
|
||||||
|
};
|
||||||
|
'while_let: while let Some(_) = Some(()) {
|
||||||
|
//~^ WARN unused label
|
||||||
|
break foo;
|
||||||
|
//~^ ERROR `break` with value from a `while` loop
|
||||||
|
}
|
||||||
|
'for_loop: for _ in 0..3 {
|
||||||
|
//~^ WARN unused label
|
||||||
|
break foo;
|
||||||
|
//~^ ERROR `break` with value from a `for` loop
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,47 +1,206 @@
|
||||||
error[E0425]: cannot find value `LOOP` in this scope
|
|
||||||
--> $DIR/label_misspelled.rs:3:9
|
|
||||||
|
|
|
||||||
LL | LOOP;
|
|
||||||
| ^^^^
|
|
||||||
| |
|
|
||||||
| not found in this scope
|
|
||||||
| help: a label with a similar name exists: `'LOOP`
|
|
||||||
|
|
||||||
error[E0425]: cannot find value `while_loop` in this scope
|
error[E0425]: cannot find value `while_loop` in this scope
|
||||||
--> $DIR/label_misspelled.rs:7:9
|
--> $DIR/label_misspelled.rs:6:9
|
||||||
|
|
|
|
||||||
|
LL | 'while_loop: while true {
|
||||||
|
| ----------- a label with a similar name exists
|
||||||
|
LL |
|
||||||
LL | while_loop;
|
LL | while_loop;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^ not found in this scope
|
||||||
| |
|
|
||||||
| not found in this scope
|
|
||||||
| help: a label with a similar name exists: `'while_loop`
|
|
||||||
|
|
||||||
error[E0425]: cannot find value `while_let` in this scope
|
error[E0425]: cannot find value `while_let` in this scope
|
||||||
--> $DIR/label_misspelled.rs:11:9
|
--> $DIR/label_misspelled.rs:11:9
|
||||||
|
|
|
|
||||||
|
LL | 'while_let: while let Some(_) = Some(()) {
|
||||||
|
| ---------- a label with a similar name exists
|
||||||
|
LL |
|
||||||
LL | while_let;
|
LL | while_let;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^ not found in this scope
|
||||||
| |
|
|
||||||
| not found in this scope
|
|
||||||
| help: a label with a similar name exists: `'while_let`
|
|
||||||
|
|
||||||
error[E0425]: cannot find value `for_loop` in this scope
|
error[E0425]: cannot find value `for_loop` in this scope
|
||||||
--> $DIR/label_misspelled.rs:15:9
|
--> $DIR/label_misspelled.rs:16:9
|
||||||
|
|
|
|
||||||
|
LL | 'for_loop: for _ in 0..3 {
|
||||||
|
| --------- a label with a similar name exists
|
||||||
|
LL |
|
||||||
LL | for_loop;
|
LL | for_loop;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^ not found in this scope
|
||||||
| |
|
|
||||||
| not found in this scope
|
error[E0425]: cannot find value `LOOP` in this scope
|
||||||
| help: a label with a similar name exists: `'for_loop`
|
--> $DIR/label_misspelled.rs:21:9
|
||||||
|
|
|
||||||
|
LL | 'LOOP: loop {
|
||||||
|
| ----- a label with a similar name exists
|
||||||
|
LL |
|
||||||
|
LL | LOOP;
|
||||||
|
| ^^^^ not found in this scope
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `LOOP` in this scope
|
||||||
|
--> $DIR/label_misspelled.rs:28:15
|
||||||
|
|
|
||||||
|
LL | 'LOOP: loop {
|
||||||
|
| ----- a label with a similar name exists
|
||||||
|
LL | break LOOP;
|
||||||
|
| ^^^^
|
||||||
|
| |
|
||||||
|
| not found in this scope
|
||||||
|
| help: use the similarly named label: `'LOOP`
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `while_loop` in this scope
|
||||||
|
--> $DIR/label_misspelled.rs:32:15
|
||||||
|
|
|
||||||
|
LL | 'while_loop: while true {
|
||||||
|
| ----------- a label with a similar name exists
|
||||||
|
LL | break while_loop;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| not found in this scope
|
||||||
|
| help: use the similarly named label: `'while_loop`
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `while_let` in this scope
|
||||||
|
--> $DIR/label_misspelled.rs:36:15
|
||||||
|
|
|
||||||
|
LL | 'while_let: while let Some(_) = Some(()) {
|
||||||
|
| ---------- a label with a similar name exists
|
||||||
|
LL | break while_let;
|
||||||
|
| ^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| not found in this scope
|
||||||
|
| help: use the similarly named label: `'while_let`
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `for_loop` in this scope
|
||||||
|
--> $DIR/label_misspelled.rs:40:15
|
||||||
|
|
|
||||||
|
LL | 'for_loop: for _ in 0..3 {
|
||||||
|
| --------- a label with a similar name exists
|
||||||
|
LL | break for_loop;
|
||||||
|
| ^^^^^^^^
|
||||||
|
| |
|
||||||
|
| not found in this scope
|
||||||
|
| help: use the similarly named label: `'for_loop`
|
||||||
|
|
||||||
|
warning: unused label
|
||||||
|
--> $DIR/label_misspelled.rs:4:5
|
||||||
|
|
|
||||||
|
LL | 'while_loop: while true {
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/label_misspelled.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![warn(unused_labels)]
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
warning: denote infinite loops with `loop { ... }`
|
warning: denote infinite loops with `loop { ... }`
|
||||||
--> $DIR/label_misspelled.rs:6:5
|
--> $DIR/label_misspelled.rs:4:5
|
||||||
|
|
|
|
||||||
LL | 'while_loop: while true {
|
LL | 'while_loop: while true {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
|
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
|
||||||
|
|
|
|
||||||
= note: `#[warn(while_true)]` on by default
|
= note: `#[warn(while_true)]` on by default
|
||||||
|
|
||||||
error: aborting due to 4 previous errors; 1 warning emitted
|
warning: unused label
|
||||||
|
--> $DIR/label_misspelled.rs:9:5
|
||||||
|
|
|
||||||
|
LL | 'while_let: while let Some(_) = Some(()) {
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0425`.
|
warning: unused label
|
||||||
|
--> $DIR/label_misspelled.rs:14:5
|
||||||
|
|
|
||||||
|
LL | 'for_loop: for _ in 0..3 {
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
||||||
|
warning: unused label
|
||||||
|
--> $DIR/label_misspelled.rs:19:5
|
||||||
|
|
|
||||||
|
LL | 'LOOP: loop {
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
warning: denote infinite loops with `loop { ... }`
|
||||||
|
--> $DIR/label_misspelled.rs:31:5
|
||||||
|
|
|
||||||
|
LL | 'while_loop: while true {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
|
||||||
|
|
||||||
|
warning: unused label
|
||||||
|
--> $DIR/label_misspelled.rs:47:5
|
||||||
|
|
|
||||||
|
LL | 'while_loop: while true {
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
warning: denote infinite loops with `loop { ... }`
|
||||||
|
--> $DIR/label_misspelled.rs:47:5
|
||||||
|
|
|
||||||
|
LL | 'while_loop: while true {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
|
||||||
|
|
||||||
|
warning: unused label
|
||||||
|
--> $DIR/label_misspelled.rs:52:5
|
||||||
|
|
|
||||||
|
LL | 'while_let: while let Some(_) = Some(()) {
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
warning: unused label
|
||||||
|
--> $DIR/label_misspelled.rs:57:5
|
||||||
|
|
|
||||||
|
LL | 'for_loop: for _ in 0..3 {
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0571]: `break` with value from a `while` loop
|
||||||
|
--> $DIR/label_misspelled.rs:49:9
|
||||||
|
|
|
||||||
|
LL | 'while_loop: while true {
|
||||||
|
| ----------------------- you can't `break` with a value in a `while` loop
|
||||||
|
LL |
|
||||||
|
LL | break foo;
|
||||||
|
| ^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||||
|
|
|
||||||
|
help: use `break` on its own without a value inside this `while` loop
|
||||||
|
|
|
||||||
|
LL | break;
|
||||||
|
| ^^^^^
|
||||||
|
help: alternatively, you might have meant to use the available loop label
|
||||||
|
|
|
||||||
|
LL | break 'while_loop;
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0571]: `break` with value from a `while` loop
|
||||||
|
--> $DIR/label_misspelled.rs:54:9
|
||||||
|
|
|
||||||
|
LL | 'while_let: while let Some(_) = Some(()) {
|
||||||
|
| ---------------------------------------- you can't `break` with a value in a `while` loop
|
||||||
|
LL |
|
||||||
|
LL | break foo;
|
||||||
|
| ^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||||
|
|
|
||||||
|
help: use `break` on its own without a value inside this `while` loop
|
||||||
|
|
|
||||||
|
LL | break;
|
||||||
|
| ^^^^^
|
||||||
|
help: alternatively, you might have meant to use the available loop label
|
||||||
|
|
|
||||||
|
LL | break 'while_let;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0571]: `break` with value from a `for` loop
|
||||||
|
--> $DIR/label_misspelled.rs:59:9
|
||||||
|
|
|
||||||
|
LL | 'for_loop: for _ in 0..3 {
|
||||||
|
| ------------------------ you can't `break` with a value in a `for` loop
|
||||||
|
LL |
|
||||||
|
LL | break foo;
|
||||||
|
| ^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||||
|
|
|
||||||
|
help: use `break` on its own without a value inside this `for` loop
|
||||||
|
|
|
||||||
|
LL | break;
|
||||||
|
| ^^^^^
|
||||||
|
help: alternatively, you might have meant to use the available loop label
|
||||||
|
|
|
||||||
|
LL | break 'for_loop;
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 11 previous errors; 10 warnings emitted
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0425, E0571.
|
||||||
|
For more information about an error, try `rustc --explain E0425`.
|
||||||
|
|
16
src/test/ui/label/label_misspelled_2.rs
Normal file
16
src/test/ui/label/label_misspelled_2.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#![warn(unused_labels)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
'a: for _ in 0..1 {
|
||||||
|
break 'a;
|
||||||
|
}
|
||||||
|
'b: for _ in 0..1 {
|
||||||
|
break b; //~ ERROR cannot find value `b` in this scope
|
||||||
|
}
|
||||||
|
c: for _ in 0..1 { //~ ERROR malformed loop label
|
||||||
|
break 'c;
|
||||||
|
}
|
||||||
|
d: for _ in 0..1 { //~ ERROR malformed loop label
|
||||||
|
break d; //~ ERROR cannot find value `d` in this scope
|
||||||
|
}
|
||||||
|
}
|
37
src/test/ui/label/label_misspelled_2.stderr
Normal file
37
src/test/ui/label/label_misspelled_2.stderr
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
error: malformed loop label
|
||||||
|
--> $DIR/label_misspelled_2.rs:10:5
|
||||||
|
|
|
||||||
|
LL | c: for _ in 0..1 {
|
||||||
|
| ^ help: use the correct loop label format: `'c`
|
||||||
|
|
||||||
|
error: malformed loop label
|
||||||
|
--> $DIR/label_misspelled_2.rs:13:5
|
||||||
|
|
|
||||||
|
LL | d: for _ in 0..1 {
|
||||||
|
| ^ help: use the correct loop label format: `'d`
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `b` in this scope
|
||||||
|
--> $DIR/label_misspelled_2.rs:8:15
|
||||||
|
|
|
||||||
|
LL | 'b: for _ in 0..1 {
|
||||||
|
| -- a label with a similar name exists
|
||||||
|
LL | break b;
|
||||||
|
| ^
|
||||||
|
| |
|
||||||
|
| not found in this scope
|
||||||
|
| help: use the similarly named label: `'b`
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `d` in this scope
|
||||||
|
--> $DIR/label_misspelled_2.rs:14:15
|
||||||
|
|
|
||||||
|
LL | d: for _ in 0..1 {
|
||||||
|
| - a label with a similar name exists
|
||||||
|
LL | break d;
|
||||||
|
| ^
|
||||||
|
| |
|
||||||
|
| not found in this scope
|
||||||
|
| help: use the similarly named label: `'d`
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0425`.
|
|
@ -1,10 +1,12 @@
|
||||||
error[E0571]: `break` with value from a `for` loop
|
error[E0571]: `break` with value from a `for` loop
|
||||||
--> $DIR/loop-break-value-no-repeat.rs:12:9
|
--> $DIR/loop-break-value-no-repeat.rs:12:9
|
||||||
|
|
|
|
||||||
|
LL | for _ in &[1,2,3] {
|
||||||
|
| ----------------- you can't `break` with a value in a `for` loop
|
||||||
LL | break 22
|
LL | break 22
|
||||||
| ^^^^^^^^ can only break with a value inside `loop` or breakable block
|
| ^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||||
|
|
|
|
||||||
help: instead, use `break` on its own without a value inside this `for` loop
|
help: use `break` on its own without a value inside this `for` loop
|
||||||
|
|
|
|
||||||
LL | break
|
LL | break
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
|
@ -94,6 +94,5 @@ fn main() {
|
||||||
'LOOP: for _ in 0 .. 9 {
|
'LOOP: for _ in 0 .. 9 {
|
||||||
break LOOP;
|
break LOOP;
|
||||||
//~^ ERROR cannot find value `LOOP` in this scope
|
//~^ ERROR cannot find value `LOOP` in this scope
|
||||||
//~| ERROR `break` with value from a `for` loop
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
error[E0425]: cannot find value `LOOP` in this scope
|
error[E0425]: cannot find value `LOOP` in this scope
|
||||||
--> $DIR/loop-break-value.rs:95:15
|
--> $DIR/loop-break-value.rs:95:15
|
||||||
|
|
|
|
||||||
|
LL | 'LOOP: for _ in 0 .. 9 {
|
||||||
|
| ----- a label with a similar name exists
|
||||||
LL | break LOOP;
|
LL | break LOOP;
|
||||||
| ^^^^
|
| ^^^^
|
||||||
| |
|
| |
|
||||||
| not found in this scope
|
| not found in this scope
|
||||||
| help: a label with a similar name exists: `'LOOP`
|
| help: use the similarly named label: `'LOOP`
|
||||||
|
|
||||||
warning: denote infinite loops with `loop { ... }`
|
warning: denote infinite loops with `loop { ... }`
|
||||||
--> $DIR/loop-break-value.rs:26:5
|
--> $DIR/loop-break-value.rs:26:5
|
||||||
|
@ -18,32 +20,44 @@ LL | 'while_loop: while true {
|
||||||
error[E0571]: `break` with value from a `while` loop
|
error[E0571]: `break` with value from a `while` loop
|
||||||
--> $DIR/loop-break-value.rs:28:9
|
--> $DIR/loop-break-value.rs:28:9
|
||||||
|
|
|
|
||||||
|
LL | 'while_loop: while true {
|
||||||
|
| ----------------------- you can't `break` with a value in a `while` loop
|
||||||
|
LL | break;
|
||||||
LL | break ();
|
LL | break ();
|
||||||
| ^^^^^^^^ can only break with a value inside `loop` or breakable block
|
| ^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||||
|
|
|
|
||||||
help: instead, use `break` on its own without a value inside this `while` loop
|
help: use `break` on its own without a value inside this `while` loop
|
||||||
|
|
|
|
||||||
LL | break;
|
LL | break;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
help: alternatively, you might have meant to use the available loop label
|
||||||
|
|
|
||||||
|
LL | break 'while_loop;
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0571]: `break` with value from a `while` loop
|
error[E0571]: `break` with value from a `while` loop
|
||||||
--> $DIR/loop-break-value.rs:30:13
|
--> $DIR/loop-break-value.rs:30:13
|
||||||
|
|
|
|
||||||
|
LL | 'while_loop: while true {
|
||||||
|
| ----------------------- you can't `break` with a value in a `while` loop
|
||||||
|
...
|
||||||
LL | break 'while_loop 123;
|
LL | break 'while_loop 123;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
| ^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||||
|
|
|
|
||||||
help: instead, use `break` on its own without a value inside this `while` loop
|
help: use `break` on its own without a value inside this `while` loop
|
||||||
|
|
|
|
||||||
LL | break;
|
LL | break 'while_loop;
|
||||||
| ^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0571]: `break` with value from a `while` loop
|
error[E0571]: `break` with value from a `while` loop
|
||||||
--> $DIR/loop-break-value.rs:38:12
|
--> $DIR/loop-break-value.rs:38:12
|
||||||
|
|
|
|
||||||
|
LL | while let Some(_) = Some(()) {
|
||||||
|
| ---------------------------- you can't `break` with a value in a `while` loop
|
||||||
LL | if break () {
|
LL | if break () {
|
||||||
| ^^^^^^^^ can only break with a value inside `loop` or breakable block
|
| ^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||||
|
|
|
|
||||||
help: instead, use `break` on its own without a value inside this `while` loop
|
help: use `break` on its own without a value inside this `while` loop
|
||||||
|
|
|
|
||||||
LL | if break {
|
LL | if break {
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -51,10 +65,12 @@ LL | if break {
|
||||||
error[E0571]: `break` with value from a `while` loop
|
error[E0571]: `break` with value from a `while` loop
|
||||||
--> $DIR/loop-break-value.rs:43:9
|
--> $DIR/loop-break-value.rs:43:9
|
||||||
|
|
|
|
||||||
|
LL | while let Some(_) = Some(()) {
|
||||||
|
| ---------------------------- you can't `break` with a value in a `while` loop
|
||||||
LL | break None;
|
LL | break None;
|
||||||
| ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
| ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||||
|
|
|
|
||||||
help: instead, use `break` on its own without a value inside this `while` loop
|
help: use `break` on its own without a value inside this `while` loop
|
||||||
|
|
|
|
||||||
LL | break;
|
LL | break;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -62,21 +78,26 @@ LL | break;
|
||||||
error[E0571]: `break` with value from a `while` loop
|
error[E0571]: `break` with value from a `while` loop
|
||||||
--> $DIR/loop-break-value.rs:49:13
|
--> $DIR/loop-break-value.rs:49:13
|
||||||
|
|
|
|
||||||
|
LL | 'while_let_loop: while let Some(_) = Some(()) {
|
||||||
|
| --------------------------------------------- you can't `break` with a value in a `while` loop
|
||||||
|
LL | loop {
|
||||||
LL | break 'while_let_loop "nope";
|
LL | break 'while_let_loop "nope";
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||||
|
|
|
|
||||||
help: instead, use `break` on its own without a value inside this `while` loop
|
help: use `break` on its own without a value inside this `while` loop
|
||||||
|
|
|
|
||||||
LL | break;
|
LL | break 'while_let_loop;
|
||||||
| ^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0571]: `break` with value from a `for` loop
|
error[E0571]: `break` with value from a `for` loop
|
||||||
--> $DIR/loop-break-value.rs:56:9
|
--> $DIR/loop-break-value.rs:56:9
|
||||||
|
|
|
|
||||||
|
LL | for _ in &[1,2,3] {
|
||||||
|
| ----------------- you can't `break` with a value in a `for` loop
|
||||||
LL | break ();
|
LL | break ();
|
||||||
| ^^^^^^^^ can only break with a value inside `loop` or breakable block
|
| ^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||||
|
|
|
|
||||||
help: instead, use `break` on its own without a value inside this `for` loop
|
help: use `break` on its own without a value inside this `for` loop
|
||||||
|
|
|
|
||||||
LL | break;
|
LL | break;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -84,10 +105,13 @@ LL | break;
|
||||||
error[E0571]: `break` with value from a `for` loop
|
error[E0571]: `break` with value from a `for` loop
|
||||||
--> $DIR/loop-break-value.rs:57:9
|
--> $DIR/loop-break-value.rs:57:9
|
||||||
|
|
|
|
||||||
|
LL | for _ in &[1,2,3] {
|
||||||
|
| ----------------- you can't `break` with a value in a `for` loop
|
||||||
|
LL | break ();
|
||||||
LL | break [()];
|
LL | break [()];
|
||||||
| ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
| ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||||
|
|
|
|
||||||
help: instead, use `break` on its own without a value inside this `for` loop
|
help: use `break` on its own without a value inside this `for` loop
|
||||||
|
|
|
|
||||||
LL | break;
|
LL | break;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -95,24 +119,16 @@ LL | break;
|
||||||
error[E0571]: `break` with value from a `for` loop
|
error[E0571]: `break` with value from a `for` loop
|
||||||
--> $DIR/loop-break-value.rs:64:13
|
--> $DIR/loop-break-value.rs:64:13
|
||||||
|
|
|
|
||||||
|
LL | 'for_loop: for _ in &[1,2,3] {
|
||||||
|
| ---------------------------- you can't `break` with a value in a `for` loop
|
||||||
|
...
|
||||||
LL | break 'for_loop Some(17);
|
LL | break 'for_loop Some(17);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
||||||
|
|
|
|
||||||
help: instead, use `break` on its own without a value inside this `for` loop
|
help: use `break` on its own without a value inside this `for` loop
|
||||||
|
|
|
|
||||||
LL | break;
|
LL | break 'for_loop;
|
||||||
| ^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0571]: `break` with value from a `for` loop
|
|
||||||
--> $DIR/loop-break-value.rs:95:9
|
|
||||||
|
|
|
||||||
LL | break LOOP;
|
|
||||||
| ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
|
|
||||||
|
|
|
||||||
help: instead, use `break` on its own without a value inside this `for` loop
|
|
||||||
|
|
|
||||||
LL | break;
|
|
||||||
| ^^^^^
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/loop-break-value.rs:4:31
|
--> $DIR/loop-break-value.rs:4:31
|
||||||
|
@ -171,7 +187,7 @@ LL | break;
|
||||||
| expected integer, found `()`
|
| expected integer, found `()`
|
||||||
| help: give it a value of the expected type: `break value`
|
| help: give it a value of the expected type: `break value`
|
||||||
|
|
||||||
error: aborting due to 18 previous errors; 1 warning emitted
|
error: aborting due to 17 previous errors; 1 warning emitted
|
||||||
|
|
||||||
Some errors have detailed explanations: E0308, E0425, E0571.
|
Some errors have detailed explanations: E0308, E0425, E0571.
|
||||||
For more information about an error, try `rustc --explain E0308`.
|
For more information about an error, try `rustc --explain E0308`.
|
||||||
|
|
|
@ -533,7 +533,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for never_loop
|
// check for never_loop
|
||||||
if let ExprKind::Loop(ref block, _, _) = expr.kind {
|
if let ExprKind::Loop(ref block, _, _, _) = expr.kind {
|
||||||
match never_loop_block(block, expr.hir_id) {
|
match never_loop_block(block, expr.hir_id) {
|
||||||
NeverLoopResult::AlwaysBreak => span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"),
|
NeverLoopResult::AlwaysBreak => span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"),
|
||||||
NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
|
NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
|
||||||
|
@ -543,7 +543,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
|
||||||
// check for `loop { if let {} else break }` that could be `while let`
|
// check for `loop { if let {} else break }` that could be `while let`
|
||||||
// (also matches an explicit "match" instead of "if let")
|
// (also matches an explicit "match" instead of "if let")
|
||||||
// (even if the "match" or "if let" is used for declaration)
|
// (even if the "match" or "if let" is used for declaration)
|
||||||
if let ExprKind::Loop(ref block, _, LoopSource::Loop) = expr.kind {
|
if let ExprKind::Loop(ref block, _, LoopSource::Loop, _) = expr.kind {
|
||||||
// also check for empty `loop {}` statements, skipping those in #[panic_handler]
|
// also check for empty `loop {}` statements, skipping those in #[panic_handler]
|
||||||
if block.stmts.is_empty() && block.expr.is_none() && !is_in_panic_handler(cx, expr) {
|
if block.stmts.is_empty() && block.expr.is_none() && !is_in_panic_handler(cx, expr) {
|
||||||
let msg = "empty `loop {}` wastes CPU cycles";
|
let msg = "empty `loop {}` wastes CPU cycles";
|
||||||
|
@ -738,7 +738,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
|
||||||
| ExprKind::Assign(ref e1, ref e2, _)
|
| ExprKind::Assign(ref e1, ref e2, _)
|
||||||
| ExprKind::AssignOp(_, ref e1, ref e2)
|
| ExprKind::AssignOp(_, ref e1, ref e2)
|
||||||
| ExprKind::Index(ref e1, ref e2) => never_loop_expr_all(&mut [&**e1, &**e2].iter().cloned(), main_loop_id),
|
| ExprKind::Index(ref e1, ref e2) => never_loop_expr_all(&mut [&**e1, &**e2].iter().cloned(), main_loop_id),
|
||||||
ExprKind::Loop(ref b, _, _) => {
|
ExprKind::Loop(ref b, _, _, _) => {
|
||||||
// Break can come from the inner loop so remove them.
|
// Break can come from the inner loop so remove them.
|
||||||
absorb_break(&never_loop_block(b, main_loop_id))
|
absorb_break(&never_loop_block(b, main_loop_id))
|
||||||
},
|
},
|
||||||
|
@ -1314,7 +1314,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
|
||||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||||
match &expr.kind {
|
match &expr.kind {
|
||||||
// Non-determinism may occur ... don't give a lint
|
// Non-determinism may occur ... don't give a lint
|
||||||
ExprKind::Loop(_, _, _) | ExprKind::Match(_, _, _) => self.should_lint = false,
|
ExprKind::Loop(..) | ExprKind::Match(..) => self.should_lint = false,
|
||||||
ExprKind::Block(block, _) => self.visit_block(block),
|
ExprKind::Block(block, _) => self.visit_block(block),
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,7 +221,7 @@ where
|
||||||
{
|
{
|
||||||
if let ast::ExprKind::While(_, loop_block, label)
|
if let ast::ExprKind::While(_, loop_block, label)
|
||||||
| ast::ExprKind::ForLoop(_, _, loop_block, label)
|
| ast::ExprKind::ForLoop(_, _, loop_block, label)
|
||||||
| ast::ExprKind::Loop(loop_block, label) = &expr.kind
|
| ast::ExprKind::Loop(loop_block, label, ..) = &expr.kind
|
||||||
{
|
{
|
||||||
func(loop_block, label.as_ref());
|
func(loop_block, label.as_ref());
|
||||||
}
|
}
|
||||||
|
|
|
@ -325,7 +325,7 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut
|
||||||
| ExprKind::Field(ref e, _)
|
| ExprKind::Field(ref e, _)
|
||||||
| ExprKind::AddrOf(_, _, ref e)
|
| ExprKind::AddrOf(_, _, ref e)
|
||||||
| ExprKind::Box(ref e) => check_expr(cx, e, bindings),
|
| ExprKind::Box(ref e) => check_expr(cx, e, bindings),
|
||||||
ExprKind::Block(ref block, _) | ExprKind::Loop(ref block, _, _) => check_block(cx, block, bindings),
|
ExprKind::Block(ref block, _) | ExprKind::Loop(ref block, ..) => check_block(cx, block, bindings),
|
||||||
// ExprKind::Call
|
// ExprKind::Call
|
||||||
// ExprKind::MethodCall
|
// ExprKind::MethodCall
|
||||||
ExprKind::Array(v) | ExprKind::Tup(v) => {
|
ExprKind::Array(v) | ExprKind::Tup(v) => {
|
||||||
|
|
|
@ -317,7 +317,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
|
||||||
self.current = cast_pat;
|
self.current = cast_pat;
|
||||||
self.visit_expr(expr);
|
self.visit_expr(expr);
|
||||||
},
|
},
|
||||||
ExprKind::Loop(ref body, _, desugaring) => {
|
ExprKind::Loop(ref body, _, desugaring, _) => {
|
||||||
let body_pat = self.next("body");
|
let body_pat = self.next("body");
|
||||||
let des = loop_desugaring_name(desugaring);
|
let des = loop_desugaring_name(desugaring);
|
||||||
let label_pat = self.next("label");
|
let label_pat = self.next("label");
|
||||||
|
|
|
@ -142,7 +142,7 @@ pub fn for_loop<'tcx>(
|
||||||
if let hir::ExprKind::Match(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
|
if let hir::ExprKind::Match(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
|
||||||
if let hir::ExprKind::Call(_, ref iterargs) = iterexpr.kind;
|
if let hir::ExprKind::Call(_, ref iterargs) = iterexpr.kind;
|
||||||
if iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none();
|
if iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none();
|
||||||
if let hir::ExprKind::Loop(ref block, _, _) = arms[0].body.kind;
|
if let hir::ExprKind::Loop(ref block, ..) = arms[0].body.kind;
|
||||||
if block.expr.is_none();
|
if block.expr.is_none();
|
||||||
if let [ _, _, ref let_stmt, ref body ] = *block.stmts;
|
if let [ _, _, ref let_stmt, ref body ] = *block.stmts;
|
||||||
if let hir::StmtKind::Local(ref local) = let_stmt.kind;
|
if let hir::StmtKind::Local(ref local) = let_stmt.kind;
|
||||||
|
@ -158,7 +158,7 @@ pub fn for_loop<'tcx>(
|
||||||
/// `while cond { body }` becomes `(cond, body)`.
|
/// `while cond { body }` becomes `(cond, body)`.
|
||||||
pub fn while_loop<'tcx>(expr: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>)> {
|
pub fn while_loop<'tcx>(expr: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>)> {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let hir::ExprKind::Loop(block, _, hir::LoopSource::While) = &expr.kind;
|
if let hir::ExprKind::Loop(block, _, hir::LoopSource::While, _) = &expr.kind;
|
||||||
if let hir::Block { expr: Some(expr), .. } = &**block;
|
if let hir::Block { expr: Some(expr), .. } = &**block;
|
||||||
if let hir::ExprKind::Match(cond, arms, hir::MatchSource::WhileDesugar) = &expr.kind;
|
if let hir::ExprKind::Match(cond, arms, hir::MatchSource::WhileDesugar) = &expr.kind;
|
||||||
if let hir::ExprKind::DropTemps(cond) = &cond.kind;
|
if let hir::ExprKind::DropTemps(cond) = &cond.kind;
|
||||||
|
|
|
@ -123,7 +123,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
|
self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
|
||||||
},
|
},
|
||||||
(&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
|
(&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
|
||||||
(&ExprKind::Loop(ref lb, ref ll, ref lls), &ExprKind::Loop(ref rb, ref rl, ref rls)) => {
|
(&ExprKind::Loop(ref lb, ref ll, ref lls, _), &ExprKind::Loop(ref rb, ref rl, ref rls, _)) => {
|
||||||
lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
|
lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
|
||||||
},
|
},
|
||||||
(&ExprKind::Match(ref le, ref la, ref ls), &ExprKind::Match(ref re, ref ra, ref rs)) => {
|
(&ExprKind::Match(ref le, ref la, ref ls), &ExprKind::Match(ref re, ref ra, ref rs)) => {
|
||||||
|
@ -560,7 +560,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||||
ExprKind::Lit(ref l) => {
|
ExprKind::Lit(ref l) => {
|
||||||
l.node.hash(&mut self.s);
|
l.node.hash(&mut self.s);
|
||||||
},
|
},
|
||||||
ExprKind::Loop(ref b, ref i, _) => {
|
ExprKind::Loop(ref b, ref i, ..) => {
|
||||||
self.hash_block(b);
|
self.hash_block(b);
|
||||||
if let Some(i) = *i {
|
if let Some(i) = *i {
|
||||||
self.hash_name(i.ident.name);
|
self.hash_name(i.ident.name);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue